@hsu-react/ui 0.0.5 → 0.0.8

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.
@@ -22,6 +22,25 @@ import usePermissions from "../../../hooks/usePermissions";
22
22
  import { jsx as _jsx } from "react/jsx-runtime";
23
23
  import { Fragment as _Fragment } from "react/jsx-runtime";
24
24
  import { jsxs as _jsxs } from "react/jsx-runtime";
25
+ // measureAlign 列:与表体、autoWidth 标题测量一致,统一按 14px 测量
26
+ var MEASURE_ALIGN_FONT_SIZE = 14;
27
+ // Canvas measureText 仅返回 advance width,较 DOM 实际渲染偏窄约 1px,补 2px 缓冲避免最宽行被挤压
28
+ var MEASURE_ALIGN_BUFFER_PX = 2;
29
+
30
+ // 计算 measureAlign 列的定宽(取本列所有行展示文本的最大像素宽)
31
+ var getMeasureAlignWidth = function getMeasureAlignWidth(column, dataSource) {
32
+ if (!(dataSource !== null && dataSource !== void 0 && dataSource.length)) return 0;
33
+ var measureText = column.measureText,
34
+ dataIndex = column.dataIndex;
35
+ var max = dataSource.reduce(function (acc, record) {
36
+ var _ref;
37
+ var text = measureText ? measureText(record) : String((_ref = dataIndex ? record[dataIndex] : "") !== null && _ref !== void 0 ? _ref : "");
38
+ return Math.max(acc, get_string_size(text, {
39
+ size: MEASURE_ALIGN_FONT_SIZE
40
+ }).width);
41
+ }, 0);
42
+ return max > 0 ? Math.ceil(max) + MEASURE_ALIGN_BUFFER_PX : 0;
43
+ };
25
44
  var useTableColumns = function useTableColumns(params) {
26
45
  var _params$columns = params.columns,
27
46
  columns = _params$columns === void 0 ? [] : _params$columns,
@@ -77,10 +96,10 @@ var useTableColumns = function useTableColumns(params) {
77
96
  var _cloned$map;
78
97
  var cloned = cloneDeep(columns);
79
98
  var newColumns = cloned === null || cloned === void 0 || (_cloned$map = cloned.map(function (item, idx) {
80
- var _ref, _item$key;
99
+ var _ref2, _item$key;
81
100
  return _objectSpread(_objectSpread({}, item), {}, {
82
101
  width: !item.width ? "100%" : item.width,
83
- key: (_ref = (_item$key = item.key) !== null && _item$key !== void 0 ? _item$key : item.dataIndex) !== null && _ref !== void 0 ? _ref : "col_".concat(idx),
102
+ key: (_ref2 = (_item$key = item.key) !== null && _item$key !== void 0 ? _item$key : item.dataIndex) !== null && _ref2 !== void 0 ? _ref2 : "col_".concat(idx),
84
103
  hidden: !checkPermission(item.hasPermi) || item.hidden,
85
104
  ellipsis: typeof item.ellipsis === "boolean" ? item.ellipsis : true
86
105
  });
@@ -220,12 +239,33 @@ var useTableColumns = function useTableColumns(params) {
220
239
  return (_enhancedColumns3 = enhancedColumns) === null || _enhancedColumns3 === void 0 ? void 0 : _enhancedColumns3.map(function (column) {
221
240
  var orderKey = column.orderKey || column.dataIndex;
222
241
  var isOrderColumn = orderKey && orderKey !== "serialNumber";
242
+
243
+ // measureAlign 列:把展示内容包进定宽右对齐块(块随列 align 居中),各行右边缘对齐。
244
+ // 不适用于 render 返回 { children, rowSpan } 这类 RenderedCell 的合并单元格场景。
245
+ var render = column.render;
246
+ if (column.measureAlign) {
247
+ var cellWidth = getMeasureAlignWidth(column, dataSource);
248
+ if (cellWidth > 0) {
249
+ var innerRender = column.render;
250
+ render = function render(value, record, index) {
251
+ return /*#__PURE__*/_jsx("span", {
252
+ style: {
253
+ display: "inline-block",
254
+ width: cellWidth,
255
+ textAlign: "right"
256
+ },
257
+ children: innerRender ? innerRender(value, record, index) : value
258
+ });
259
+ };
260
+ }
261
+ }
223
262
  return _objectSpread(_objectSpread({
224
263
  showSorterTooltip: false,
225
264
  sorter: typeof sorter === "boolean" ? sorter : isOrderColumn ? true : false
226
265
  }, column), {}, {
227
266
  orderKey: orderKey,
228
267
  title: renderColumnTitle(column),
268
+ render: render,
229
269
  children: column !== null && column !== void 0 && column.children ? renderColumns(column.children) : undefined,
230
270
  onCell: function onCell(record, index) {
231
271
  var _column$onCell;
@@ -241,7 +281,7 @@ var useTableColumns = function useTableColumns(params) {
241
281
  sortOrder: (order === null || order === void 0 ? void 0 : order.k) === orderKey ? (order === null || order === void 0 ? void 0 : order.t) === "desc" ? "descend" : "ascend" : undefined
242
282
  });
243
283
  });
244
- }, [enhanceColumns, serialNumberColumn, _columns, tableWidth, pagination, _pageNum, _pageSize, bordered, rowSelection, expandable, sorter, renderColumnTitle, order, mergeRowDataSource]);
284
+ }, [enhanceColumns, serialNumberColumn, _columns, tableWidth, pagination, _pageNum, _pageSize, bordered, rowSelection, expandable, sorter, renderColumnTitle, order, mergeRowDataSource, dataSource]);
245
285
 
246
286
  // 缓存渲染后的列配置
247
287
  var renderedColumns = useMemo(function () {
@@ -24,6 +24,16 @@ export interface ColumnType<RecordType> extends AntColumnType<RecordType> {
24
24
  orderKey?: string;
25
25
  fixedWidth?: boolean;
26
26
  ellipsisPosition?: "start" | "end";
27
+ /**
28
+ * 定宽对齐列:列标题随 align 居中,单元格内容放进按本列最宽内容
29
+ * 测量出的定宽块内右对齐,使各行右边缘对齐、整体在列内居中(适合数字/金额列)。
30
+ */
31
+ measureAlign?: boolean;
32
+ /**
33
+ * measureAlign 列测量宽度所用的文本。默认取 dataIndex 原始值;当单元格由 render
34
+ * 产出复合/JSX 内容(无法从 dataIndex 直接得到展示文本)时,用它提供与展示一致的文本。
35
+ */
36
+ measureText?: (record: RecordType) => string;
27
37
  }
28
38
  export interface ColumnsGroupType<RecordType> extends Omit<AntColumnGroupType<RecordType>, "children"> {
29
39
  title?: string;
@@ -39,6 +49,8 @@ export interface ColumnsGroupType<RecordType> extends Omit<AntColumnGroupType<Re
39
49
  orderKey?: string;
40
50
  fixedWidth?: boolean;
41
51
  ellipsisPosition?: "start" | "end";
52
+ measureAlign?: boolean;
53
+ measureText?: (record: RecordType) => string;
42
54
  }
43
55
  export type ColumnsType<RecordType = AnyObject> = (ColumnType<RecordType> | ColumnsGroupType<RecordType>)[];
44
56
  export interface TableProps<RecordType = AnyObject> extends Omit<AntdTableProps<RecordType>, "scroll" | "pagination" | "columns"> {
@@ -15,6 +15,26 @@ var _tableUtils = require("../_utils/tableUtils");
15
15
  var _usePermissions = _interopRequireDefault(require("../../../hooks/usePermissions"));
16
16
  var _jsxRuntime = require("react/jsx-runtime");
17
17
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18
+ // measureAlign 列:与表体、autoWidth 标题测量一致,统一按 14px 测量
19
+ const MEASURE_ALIGN_FONT_SIZE = 14;
20
+ // Canvas measureText 仅返回 advance width,较 DOM 实际渲染偏窄约 1px,补 2px 缓冲避免最宽行被挤压
21
+ const MEASURE_ALIGN_BUFFER_PX = 2;
22
+
23
+ // 计算 measureAlign 列的定宽(取本列所有行展示文本的最大像素宽)
24
+ const getMeasureAlignWidth = (column, dataSource) => {
25
+ if (!dataSource?.length) return 0;
26
+ const {
27
+ measureText,
28
+ dataIndex
29
+ } = column;
30
+ const max = dataSource.reduce((acc, record) => {
31
+ const text = measureText ? measureText(record) : String((dataIndex ? record[dataIndex] : "") ?? "");
32
+ return Math.max(acc, (0, _hsuUtils.get_string_size)(text, {
33
+ size: MEASURE_ALIGN_FONT_SIZE
34
+ }).width);
35
+ }, 0);
36
+ return max > 0 ? Math.ceil(max) + MEASURE_ALIGN_BUFFER_PX : 0;
37
+ };
18
38
  const useTableColumns = params => {
19
39
  const {
20
40
  columns = [],
@@ -195,12 +215,31 @@ const useTableColumns = params => {
195
215
  return enhancedColumns?.map(column => {
196
216
  const orderKey = column.orderKey || column.dataIndex;
197
217
  const isOrderColumn = orderKey && orderKey !== "serialNumber";
218
+
219
+ // measureAlign 列:把展示内容包进定宽右对齐块(块随列 align 居中),各行右边缘对齐。
220
+ // 不适用于 render 返回 { children, rowSpan } 这类 RenderedCell 的合并单元格场景。
221
+ let render = column.render;
222
+ if (column.measureAlign) {
223
+ const cellWidth = getMeasureAlignWidth(column, dataSource);
224
+ if (cellWidth > 0) {
225
+ const innerRender = column.render;
226
+ render = (value, record, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
227
+ style: {
228
+ display: "inline-block",
229
+ width: cellWidth,
230
+ textAlign: "right"
231
+ },
232
+ children: innerRender ? innerRender(value, record, index) : value
233
+ });
234
+ }
235
+ }
198
236
  return {
199
237
  showSorterTooltip: false,
200
238
  sorter: typeof sorter === "boolean" ? sorter : isOrderColumn ? true : false,
201
239
  ...column,
202
240
  orderKey,
203
241
  title: renderColumnTitle(column),
242
+ render,
204
243
  children: column?.children ? renderColumns(column.children) : undefined,
205
244
  onCell: (record, index) => {
206
245
  const cell = column?.onCell?.(record, index);
@@ -216,7 +255,7 @@ const useTableColumns = params => {
216
255
  sortOrder: order?.k === orderKey ? order?.t === "desc" ? "descend" : "ascend" : undefined
217
256
  };
218
257
  });
219
- }, [enhanceColumns, serialNumberColumn, _columns, tableWidth, pagination, _pageNum, _pageSize, bordered, rowSelection, expandable, sorter, renderColumnTitle, order, mergeRowDataSource]);
258
+ }, [enhanceColumns, serialNumberColumn, _columns, tableWidth, pagination, _pageNum, _pageSize, bordered, rowSelection, expandable, sorter, renderColumnTitle, order, mergeRowDataSource, dataSource]);
220
259
 
221
260
  // 缓存渲染后的列配置
222
261
  const renderedColumns = (0, _react.useMemo)(() => renderColumns((0, _lodash.cloneDeep)(_columns)), [renderColumns, _columns]);
@@ -24,6 +24,16 @@ export interface ColumnType<RecordType> extends AntColumnType<RecordType> {
24
24
  orderKey?: string;
25
25
  fixedWidth?: boolean;
26
26
  ellipsisPosition?: "start" | "end";
27
+ /**
28
+ * 定宽对齐列:列标题随 align 居中,单元格内容放进按本列最宽内容
29
+ * 测量出的定宽块内右对齐,使各行右边缘对齐、整体在列内居中(适合数字/金额列)。
30
+ */
31
+ measureAlign?: boolean;
32
+ /**
33
+ * measureAlign 列测量宽度所用的文本。默认取 dataIndex 原始值;当单元格由 render
34
+ * 产出复合/JSX 内容(无法从 dataIndex 直接得到展示文本)时,用它提供与展示一致的文本。
35
+ */
36
+ measureText?: (record: RecordType) => string;
27
37
  }
28
38
  export interface ColumnsGroupType<RecordType> extends Omit<AntColumnGroupType<RecordType>, "children"> {
29
39
  title?: string;
@@ -39,6 +49,8 @@ export interface ColumnsGroupType<RecordType> extends Omit<AntColumnGroupType<Re
39
49
  orderKey?: string;
40
50
  fixedWidth?: boolean;
41
51
  ellipsisPosition?: "start" | "end";
52
+ measureAlign?: boolean;
53
+ measureText?: (record: RecordType) => string;
42
54
  }
43
55
  export type ColumnsType<RecordType = AnyObject> = (ColumnType<RecordType> | ColumnsGroupType<RecordType>)[];
44
56
  export interface TableProps<RecordType = AnyObject> extends Omit<AntdTableProps<RecordType>, "scroll" | "pagination" | "columns"> {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hsu-react/ui",
3
- "version": "0.0.5",
3
+ "version": "0.0.8",
4
4
  "description": "一套基于 React + Ant Design 的中后台业务组件库",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -63,7 +63,7 @@
63
63
  "@emotion/cache": "^11.14.0",
64
64
  "@emotion/react": "^11.14.0",
65
65
  "@emotion/styled": "^11.14.1",
66
- "@hsu-react/single-router": "^0.0.24",
66
+ "@hsu-react/single-router": "0.0.26",
67
67
  "@iconify/json": "^2.2.385",
68
68
  "@iconify/react": "^5.0.1",
69
69
  "@uiw/codemirror-theme-vscode": "^4.25.1",
@@ -19,6 +19,30 @@ import {
19
19
  import usePermissions from "../../../hooks/usePermissions";
20
20
  import { PaginationProps } from "../_components/Pagination";
21
21
 
22
+ // measureAlign 列:与表体、autoWidth 标题测量一致,统一按 14px 测量
23
+ const MEASURE_ALIGN_FONT_SIZE = 14;
24
+ // Canvas measureText 仅返回 advance width,较 DOM 实际渲染偏窄约 1px,补 2px 缓冲避免最宽行被挤压
25
+ const MEASURE_ALIGN_BUFFER_PX = 2;
26
+
27
+ // 计算 measureAlign 列的定宽(取本列所有行展示文本的最大像素宽)
28
+ const getMeasureAlignWidth = <T extends AnyObject>(
29
+ column: ColumnType<T>,
30
+ dataSource?: readonly T[]
31
+ ): number => {
32
+ if (!dataSource?.length) return 0;
33
+ const { measureText, dataIndex } = column;
34
+ const max = dataSource.reduce((acc, record) => {
35
+ const text = measureText
36
+ ? measureText(record)
37
+ : String((dataIndex ? record[dataIndex] : "") ?? "");
38
+ return Math.max(
39
+ acc,
40
+ get_string_size(text, { size: MEASURE_ALIGN_FONT_SIZE }).width
41
+ );
42
+ }, 0);
43
+ return max > 0 ? Math.ceil(max) + MEASURE_ALIGN_BUFFER_PX : 0;
44
+ };
45
+
22
46
  interface UseTableColumnsParams<T extends AnyObject> {
23
47
  columns?: ColumnsType<T>;
24
48
  scroll?: boolean | { y: boolean };
@@ -276,6 +300,34 @@ const useTableColumns = <T extends AnyObject>(
276
300
  const orderKey = column.orderKey || column.dataIndex;
277
301
  const isOrderColumn = orderKey && orderKey !== "serialNumber";
278
302
 
303
+ // measureAlign 列:把展示内容包进定宽右对齐块(块随列 align 居中),各行右边缘对齐。
304
+ // 不适用于 render 返回 { children, rowSpan } 这类 RenderedCell 的合并单元格场景。
305
+ let render = column.render;
306
+ if (column.measureAlign) {
307
+ const cellWidth = getMeasureAlignWidth(
308
+ column as ColumnType<T>,
309
+ dataSource
310
+ );
311
+ if (cellWidth > 0) {
312
+ const innerRender = column.render;
313
+ render = (value: unknown, record: T, index: number) => (
314
+ <span
315
+ style={{
316
+ display: "inline-block",
317
+ width: cellWidth,
318
+ textAlign: "right",
319
+ }}
320
+ >
321
+ {
322
+ (innerRender
323
+ ? innerRender(value, record, index)
324
+ : value) as React.ReactNode
325
+ }
326
+ </span>
327
+ );
328
+ }
329
+ }
330
+
279
331
  return {
280
332
  showSorterTooltip: false,
281
333
  sorter:
@@ -283,6 +335,7 @@ const useTableColumns = <T extends AnyObject>(
283
335
  ...column,
284
336
  orderKey,
285
337
  title: renderColumnTitle(column),
338
+ render,
286
339
  children: column?.children
287
340
  ? renderColumns(column.children)
288
341
  : undefined,
@@ -328,6 +381,7 @@ const useTableColumns = <T extends AnyObject>(
328
381
  renderColumnTitle,
329
382
  order,
330
383
  mergeRowDataSource,
384
+ dataSource,
331
385
  ]
332
386
  );
333
387
 
@@ -45,7 +45,7 @@ export default () => (
45
45
 
46
46
  | 属性 | 说明 | 类型 | 默认值 |
47
47
  | --- | --- | --- | --- |
48
- | columns | 列配置,使用自定义 `ColumnsType`(支持 `hidden`、`sort`、`hasPermi`、`help`、`mergeRow`、`fixedWidth`、`ellipsisPosition` 等) | `ColumnsType<RecordType>` | `[]` |
48
+ | columns | 列配置,使用自定义 `ColumnsType`(支持 `hidden`、`sort`、`hasPermi`、`help`、`mergeRow`、`fixedWidth`、`ellipsisPosition`、`measureAlign`、`measureText` 等) | `ColumnsType<RecordType>` | `[]` |
49
49
  | scroll | 是否开启滚动;`{ y: false }` 可关闭纵向滚动 | `boolean \| { y: boolean }` | `false` |
50
50
  | pagination | 分页配置;为 `false` 时不展示分页 | `false \| PaginationProps` | `{}` |
51
51
  | autoWidth | 列宽自适应 | `boolean` | - |
@@ -73,4 +73,15 @@ export default () => (
73
73
  | showTotal | 自定义分页总数展示;为 `false` 时不展示 | `false \| ((total, range) => ReactNode)` | - |
74
74
  | isExpandedCellTable | 是否为展开行内嵌表格样式 | `boolean` | `false` |
75
75
 
76
+ ### ColumnType 扩展字段:measureAlign
77
+
78
+ 数字/金额/单量列适用:按本列所有行展示文本测量出最大像素宽,把单元格内容包进该定宽块内右对齐,块本身随列 `align` 居中——各行右边缘对齐、整体在列内居中。
79
+
80
+ | 字段 | 说明 | 类型 | 默认值 |
81
+ | --- | --- | --- | --- |
82
+ | measureAlign | 开启定宽右对齐(配合列 `align: "center"` 使用) | `boolean` | - |
83
+ | measureText | 测量宽度所用文本;当单元格由 `render` 产出复合/JSX 内容时,用它提供与展示一致的文本(默认取 `dataIndex` 原始值) | `(record) => string` | - |
84
+
85
+ > 注意:不适用于 `render` 返回 `{ children, rowSpan }` 这类合并单元格场景。
86
+
76
87
  > 另导出 `TableDrag`,用于行拖拽排序场景。
@@ -46,6 +46,16 @@ export interface ColumnType<RecordType> extends AntColumnType<RecordType> {
46
46
  orderKey?: string;
47
47
  fixedWidth?: boolean;
48
48
  ellipsisPosition?: "start" | "end";
49
+ /**
50
+ * 定宽对齐列:列标题随 align 居中,单元格内容放进按本列最宽内容
51
+ * 测量出的定宽块内右对齐,使各行右边缘对齐、整体在列内居中(适合数字/金额列)。
52
+ */
53
+ measureAlign?: boolean;
54
+ /**
55
+ * measureAlign 列测量宽度所用的文本。默认取 dataIndex 原始值;当单元格由 render
56
+ * 产出复合/JSX 内容(无法从 dataIndex 直接得到展示文本)时,用它提供与展示一致的文本。
57
+ */
58
+ measureText?: (record: RecordType) => string;
49
59
  }
50
60
  export interface ColumnsGroupType<RecordType>
51
61
  extends Omit<AntColumnGroupType<RecordType>, "children"> {
@@ -62,6 +72,8 @@ export interface ColumnsGroupType<RecordType>
62
72
  orderKey?: string;
63
73
  fixedWidth?: boolean;
64
74
  ellipsisPosition?: "start" | "end";
75
+ measureAlign?: boolean;
76
+ measureText?: (record: RecordType) => string;
65
77
  }
66
78
  export type ColumnsType<RecordType = AnyObject> = (
67
79
  | ColumnType<RecordType>