@canvas-components/list-table 0.3.15 → 0.3.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,14 +26,69 @@
26
26
  显式传入 `pagination.pageSize` 时以受控值为准。外部负责请求的封装(如 WWISuperTable)应在首次请求前读取缓存,初始化自己的分页状态,避免只改变显示值而请求条数不一致:
27
27
 
28
28
  ```ts
29
- import { getListTableStoredPageSize } from '@canvas-components/list-table';
29
+ import { getListTableStoredPageSize } from "@canvas-components/list-table";
30
30
 
31
- const initialPageSize = explicitPageSize ?? getListTableStoredPageSize(storageKey) ?? 10;
31
+ const initialPageSize =
32
+ explicitPageSize ?? getListTableStoredPageSize(storageKey) ?? 10;
32
33
  // 将 initialPageSize 用于首次请求和受控 pagination.pageSize。
33
34
  ```
34
35
 
35
36
  该读取方法也由 `@canvas-components/react-list-table` 导出。
36
37
 
38
+ ## 分区 CSS 样式
39
+
40
+ 原生 `ListTable` 和 `ReactListTable` 均支持 `styles`。Canvas 区域通过 CSS 属性映射到绘制参数,不创建单元格 DOM,不注入全局样式。
41
+
42
+ ```ts
43
+ styles: {
44
+ cell: { fontSize: '14px', padding: '2px 12px', borderColor: '#d9e1ec' },
45
+ header: { backgroundColor: '#f0f9ff', color: '#075985', fontWeight: 700, textAlign: 'center' },
46
+ body: { color: '#334155' },
47
+ summary: { backgroundColor: '#f0fdf4', color: '#166534', textAlign: 'right' },
48
+ activeCell: { backgroundColor: '#fef3c7', borderColor: '#d97706', borderWidth: '2px' },
49
+ activeRow: { backgroundColor: '#e0e7ff', color: '#3730a3' },
50
+ scrollVertical: { width: '14px', color: '#94a3b8', backgroundColor: '#f1f5f9', borderRadius: 4 },
51
+ scrollHorizontal: { height: '12px', color: '#64748b', backgroundColor: '#f8fafc' },
52
+ pagination: {
53
+ root: { backgroundColor: '#f8fafc', color: '#334155', fontSize: '14px' },
54
+ total: { color: '#64748b' },
55
+ pageItem: { borderRadius: 4 },
56
+ activePageItem: { backgroundColor: '#1677ff', color: '#fff' },
57
+ sizeChanger: { width: 140 },
58
+ quickJumperInput: { width: 64 },
59
+ },
60
+ }
61
+ ```
62
+
63
+ - `cell` 是表头、表体和汇总单元格的通用默认值;分区覆盖通用值,列级 `headerStyle` / `cellStyle` / `summaryStyle` 优先。
64
+ - Canvas 分区支持 `backgroundColor`、`color`、`fontSize`、`fontWeight`、`fontFamily`、`textAlign`、`verticalAlign`、`padding`、`paddingInline`、`paddingBlock`、`borderColor`、`borderWidth`。长度只支持非负数字或 `px`,`padding` 支持一值或“上下 左右”两值;不支持百分比、`em` 或 DOM 布局属性。
65
+ - `activeCell` 支持背景、文字和边框,`activeRow` 支持背景与文字;仅改变已有选中状态的绘制,不改变选择模式。校验错误提示仍优先。
66
+ - 滚动条 `color` 对应滑块、`backgroundColor` 对应槽色;纵轴 `width`、横轴 `height` 对应厚度。显式 `scrollbar.vertical/horizontal: false` 仍禁止对应轴显示。
67
+ - `pagination` 按节点直接应用 DOM CSS,使用 camelCase 属性名,数字长度按 React DOM 规则处理;仅影响当前实例。通过原生 UI 回调自行渲染分页器时,从 `PaginationConfig.styles` 读取并应用样式。当前分页占位高度仍由表格密度决定,避免设置超出该高度的高度或纵向间距。
68
+
69
+ 分页器支持以下节点:
70
+
71
+ | 节点 | 作用 |
72
+ | --------------------------- | ---------------------------------------------------- |
73
+ | `root` | 分页器根容器,颜色、字体等可向内部继承 |
74
+ | `total` | 总条数文本 |
75
+ | `pages` | 页码列表容器 |
76
+ | `pageItem` | 普通页码按钮;简易模式下为页码文本 |
77
+ | `activePageItem` | 当前页按钮,叠加并覆盖 `pageItem` |
78
+ | `prevButton` / `nextButton` | 上一页 / 下一页按钮 |
79
+ | `prevIcon` / `nextIcon` | 上一页 / 下一页箭头,通过 `borderColor` 设置箭头颜色 |
80
+ | `ellipsis` | 页码省略号 |
81
+ | `sizeChanger` | 分页尺寸选择控件,不包含弹出选项面板 |
82
+ | `quickJumper` | 快速跳转区域容器 |
83
+ | `quickJumperText` | “跳至”和“页”文本 |
84
+ | `quickJumperInput` | 跳转输入控件外框,可设置宽度、背景与边框 |
85
+
86
+ 节点样式优先于默认样式;未配置节点保持原样。独立使用 `ReactPagination` 时也支持同名 `styles`,其中 `styles.root` 优先于 `style`。
87
+
88
+ - 更新或移除 `styles` 后即时生效;不额外持久化 `styles` 对象,已有列配置缓存中的对齐设置仍优先。嵌套子表格的独立内容样式仍通过其列/内容配置指定。
89
+
90
+ 文档站“主题”示例增加了“启用分区 CSS 样式”开关,可切换验证。
91
+
37
92
  ## 安装方法
38
93
 
39
94
  ```bash
package/dist/index.cjs CHANGED
@@ -71,6 +71,87 @@ var DebugManager = class {
71
71
  console.info(`[ListTable Debug] ${label}`, payload);
72
72
  }
73
73
  };
74
+
75
+ // src/services/table-styles-service.ts
76
+ function resolveStylePixels(value) {
77
+ if (typeof value === "string" && !/^\s*\d+(?:\.\d+)?(?:px)?\s*$/.test(value))
78
+ return void 0;
79
+ const number = typeof value === "string" ? parseFloat(value) : value;
80
+ return number != null && Number.isFinite(number) && number >= 0 ? number : void 0;
81
+ }
82
+ function resolveCanvasCellStyle(style) {
83
+ if (!style) return void 0;
84
+ const padding = typeof style.padding === "string" ? style.padding.trim().split(/\s+/) : [style.padding];
85
+ const result = {
86
+ backgroundColor: style.backgroundColor,
87
+ color: style.color,
88
+ fontSize: resolveStylePixels(style.fontSize),
89
+ fontWeight: style.fontWeight == null ? void 0 : String(style.fontWeight),
90
+ fontFamily: style.fontFamily,
91
+ textAlign: style.textAlign,
92
+ verticalAlign: style.verticalAlign,
93
+ paddingInline: resolveStylePixels(style.paddingInline) ?? (padding.length <= 2 ? resolveStylePixels(padding[1] ?? padding[0]) : void 0),
94
+ paddingBlock: resolveStylePixels(style.paddingBlock) ?? (padding.length <= 2 ? resolveStylePixels(padding[0]) : void 0),
95
+ borderColor: style.borderColor,
96
+ borderWidth: resolveStylePixels(style.borderWidth)
97
+ };
98
+ return Object.fromEntries(
99
+ Object.entries(result).filter(([, value]) => value !== void 0)
100
+ );
101
+ }
102
+ function resolveListTableStyleOptions(options) {
103
+ const styles = options.styles;
104
+ if (!styles) return options;
105
+ const cell = resolveCanvasCellStyle(styles.cell) ?? {};
106
+ const header = { ...cell, ...resolveCanvasCellStyle(styles.header) };
107
+ const body = { ...cell, ...resolveCanvasCellStyle(styles.body) };
108
+ const summary = { ...cell, ...resolveCanvasCellStyle(styles.summary) };
109
+ const mapColumns = (columns) => columns.map((column) => ({
110
+ ...column,
111
+ align: column.align ?? (column.cellStyle?.textAlign ?? body.textAlign),
112
+ headerAlign: column.headerAlign ?? (column.headerStyle?.textAlign ?? column.align ?? header.textAlign),
113
+ cellStyle: { ...body, ...column.cellStyle },
114
+ headerStyle: { ...header, ...column.headerStyle },
115
+ summaryStyle: { ...summary, ...column.summaryStyle },
116
+ children: column.children ? mapColumns(column.children) : void 0
117
+ }));
118
+ const scrollbar = { ...options.scrollbar };
119
+ for (const axis of ["vertical", "horizontal"]) {
120
+ const style = axis === "vertical" ? styles.scrollVertical : styles.scrollHorizontal;
121
+ if (!style || scrollbar[axis] === false) continue;
122
+ const mapped = {
123
+ thumbColor: style.color,
124
+ trackColor: style.backgroundColor,
125
+ thickness: resolveStylePixels(
126
+ axis === "vertical" ? style.width : style.height
127
+ ),
128
+ thumbRadius: resolveStylePixels(style.borderRadius)
129
+ };
130
+ scrollbar[axis] = {
131
+ ...scrollbar[axis],
132
+ ...Object.fromEntries(
133
+ Object.entries(mapped).filter(([, value]) => value !== void 0)
134
+ )
135
+ };
136
+ }
137
+ return {
138
+ ...options,
139
+ columns: mapColumns(options.columns),
140
+ scrollbar,
141
+ theme: {
142
+ ...options.theme,
143
+ ...cell.borderColor ? { borderColor: cell.borderColor } : {},
144
+ ...cell.fontSize != null ? { fontSize: cell.fontSize } : {},
145
+ ...cell.fontFamily ? { fontFamily: cell.fontFamily } : {},
146
+ ...body.color ? { textColor: body.color } : {},
147
+ ...header.backgroundColor ? { headerBackgroundColor: header.backgroundColor } : {},
148
+ ...header.color ? { headerTextColor: header.color } : {},
149
+ ...body.backgroundColor ? { backgroundColor: body.backgroundColor } : {},
150
+ activeCellStyle: resolveCanvasCellStyle(styles.activeCell),
151
+ activeRowStyle: resolveCanvasCellStyle(styles.activeRow)
152
+ }
153
+ };
154
+ }
74
155
  function resolveColumnKey(column) {
75
156
  return column.key?.trim() || utils.stringifyDataIndex(column.dataIndex);
76
157
  }
@@ -585,15 +666,19 @@ function stretchColumnWidths(columns, containerWidth) {
585
666
  }
586
667
  const extra = containerWidth - totalWidth;
587
668
  const stretchableWidth = computeColumnWidths(stretchableColumns);
588
- const ratio = stretchableWidth > 0 ? extra / stretchableWidth : 0;
589
- for (const column of stretchableColumns) {
590
- column.width = Math.round(column.width * (1 + ratio));
591
- }
592
- const adjustedTotal = computeColumnWidths(columns);
593
- const remain = containerWidth - adjustedTotal;
594
- if (remain > 0) {
595
- stretchableColumns[stretchableColumns.length - 1].width += remain;
596
- }
669
+ let accumulatedWidth = 0;
670
+ let allocatedExtra = 0;
671
+ stretchableColumns.forEach((column, index) => {
672
+ accumulatedWidth += column.width;
673
+ const targetExtra = index === stretchableColumns.length - 1 ? extra : Math.min(
674
+ extra,
675
+ Math.floor(
676
+ extra * (stretchableWidth > 0 ? accumulatedWidth / stretchableWidth : (index + 1) / stretchableColumns.length)
677
+ )
678
+ );
679
+ column.width += targetExtra - allocatedExtra;
680
+ allocatedExtra = targetExtra;
681
+ });
597
682
  }
598
683
  function shrinkColumnWidthsToFit(columns, containerWidth) {
599
684
  let remaining = Math.max(
@@ -693,6 +778,7 @@ function normalizeColumn(column, depth, parentKey) {
693
778
  moneyFormat: column.moneyFormat,
694
779
  dataFormat: column.dataFormat,
695
780
  headerStyle: column.headerStyle,
781
+ summaryStyle: column.summaryStyle,
696
782
  summary: column.summary,
697
783
  summaryTitle: column.summaryTitle,
698
784
  meta: column.meta,
@@ -7203,10 +7289,11 @@ function roundRectPath(ctx, x, y, width, height, radius) {
7203
7289
  }
7204
7290
 
7205
7291
  // src/rendering/primitives/draw-grid.ts
7206
- function drawGridRect(ctx, rect, theme, borderColor = theme.borderColor) {
7292
+ function drawGridRect(ctx, rect, theme, borderColor = theme.borderColor, borderWidth = 1) {
7293
+ if (borderWidth <= 0) return;
7207
7294
  ctx.save();
7208
7295
  ctx.strokeStyle = borderColor;
7209
- ctx.lineWidth = 1;
7296
+ ctx.lineWidth = borderWidth;
7210
7297
  ctx.beginPath();
7211
7298
  const showTop = rect.y > 0;
7212
7299
  const showLeft = rect.x > 0;
@@ -7238,7 +7325,8 @@ function resolveHeaderTextLayout(params) {
7238
7325
  allowActions,
7239
7326
  hasFilter,
7240
7327
  contentInsetStart = 0,
7241
- contentInsetEnd = 0
7328
+ contentInsetEnd = 0,
7329
+ paddingInline = HEADER_TEXT_PADDING
7242
7330
  } = params;
7243
7331
  const contentRect = {
7244
7332
  x: rect.x + contentInsetStart,
@@ -7260,11 +7348,11 @@ function resolveHeaderTextLayout(params) {
7260
7348
  contentRect,
7261
7349
  contentVisibleRect,
7262
7350
  align,
7263
- HEADER_TEXT_PADDING
7351
+ paddingInline
7264
7352
  );
7265
7353
  const baseLayout = {
7266
7354
  align,
7267
- maxWidth: Math.max(contentVisibleRect.width - HEADER_TEXT_PADDING * 2, 12),
7355
+ maxWidth: Math.max(contentVisibleRect.width - paddingInline * 2, 12),
7268
7356
  x: baseX
7269
7357
  };
7270
7358
  if (!allowActions || !actionVisibilityState.visible || align === "left") {
@@ -7276,10 +7364,10 @@ function resolveHeaderTextLayout(params) {
7276
7364
  trailingInset: contentInsetEnd
7277
7365
  });
7278
7366
  const textRight = Math.min(
7279
- contentVisibleRect.x + contentVisibleRect.width - HEADER_TEXT_PADDING,
7280
- actionLayout.startX - HEADER_TEXT_PADDING
7367
+ contentVisibleRect.x + contentVisibleRect.width - paddingInline,
7368
+ actionLayout.startX - paddingInline
7281
7369
  );
7282
- const textLeft = contentVisibleRect.x + HEADER_TEXT_PADDING;
7370
+ const textLeft = contentVisibleRect.x + paddingInline;
7283
7371
  if (align === "center") {
7284
7372
  const centeredWidth = Math.max(
7285
7373
  Math.min(baseX - textLeft, textRight - baseX) * 2,
@@ -7414,9 +7502,15 @@ function drawHeaderCell(params, cell, clipRect) {
7414
7502
  const isRangeSelected = isHeaderCellInRange(params.rangeHighlight, cell);
7415
7503
  ctx.fillStyle = isSelected || isRangeSelected ? theme.selectionBackgroundColor : cell.node.style?.backgroundColor ?? theme.headerBackgroundColor;
7416
7504
  ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
7417
- drawGridRect(ctx, rect, theme);
7505
+ drawGridRect(
7506
+ ctx,
7507
+ rect,
7508
+ theme,
7509
+ cell.node.style?.borderColor,
7510
+ cell.node.style?.borderWidth
7511
+ );
7418
7512
  ctx.fillStyle = cell.node.style?.color ?? theme.headerTextColor;
7419
- ctx.font = `${theme.headerFontWeight} ${theme.fontSize}px ${theme.fontFamily}`;
7513
+ ctx.font = `${cell.node.style?.fontWeight ?? theme.headerFontWeight} ${cell.node.style?.fontSize ?? theme.fontSize}px ${cell.node.style?.fontFamily ?? theme.fontFamily}`;
7420
7514
  ctx.textBaseline = "middle";
7421
7515
  const visibleRect = clipRect ? intersectRects(rect, clipRect) : rect;
7422
7516
  if (!visibleRect) {
@@ -7448,6 +7542,7 @@ function drawHeaderCell(params, cell, clipRect) {
7448
7542
  allowActions: cell.node.children.length === 0,
7449
7543
  hasFilter: params.filterableColumnKeys.has(cell.node.key),
7450
7544
  contentWidth: measureHeaderContentWidth(ctx, titleContent),
7545
+ paddingInline: cell.node.style?.paddingInline,
7451
7546
  contentInsetStart: resolveHeaderContentInsetStart({
7452
7547
  columnKey: cell.node.key,
7453
7548
  hasChildren: cell.node.children.length > 0,
@@ -7459,7 +7554,7 @@ function drawHeaderCell(params, cell, clipRect) {
7459
7554
  const textY = resolveHeaderContentCenterY(
7460
7555
  rect,
7461
7556
  titleContent,
7462
- theme.fontSize,
7557
+ cell.node.style?.fontSize ?? theme.fontSize,
7463
7558
  cell.node.style?.paddingBlock ?? params.defaultPaddingBlock ?? resolveDensityPaddingBlock(cell.height),
7464
7559
  cell.node.style?.verticalAlign
7465
7560
  );
@@ -8121,6 +8216,11 @@ function drawSummarySegment(params, columns, clipRect, defaultTitleColumnKey) {
8121
8216
  function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeaderKey, summarySelected, rangeHighlight, clipRect, descriptors, inlineContentInset, defaultTitleColumnKey, textSelection) {
8122
8217
  ctx.save();
8123
8218
  const cellClip = clipRect ? intersectRects2(rect, clipRect) : rect;
8219
+ const style = column.summaryStyle;
8220
+ const fontSize = style?.fontSize ?? theme.fontSize;
8221
+ const paddingInline = style?.paddingInline ?? 12;
8222
+ const paddingBlock = style?.paddingBlock ?? 0;
8223
+ const textY = style?.verticalAlign === "top" ? rect.y + paddingBlock + fontSize / 2 : style?.verticalAlign === "bottom" ? rect.y + rect.height - paddingBlock - fontSize / 2 : rect.y + rect.height / 2;
8124
8224
  if (!cellClip) {
8125
8225
  ctx.restore();
8126
8226
  return;
@@ -8130,9 +8230,9 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
8130
8230
  column.leafIndex,
8131
8231
  (rangeHighlight ?? EMPTY_RANGE_HIGHLIGHT2).selectedColumnRange
8132
8232
  );
8133
- ctx.fillStyle = summarySelected || isHeaderColumnSelected || isColumnRangeSelected ? theme.selectionBackgroundColor : theme.headerBackgroundColor;
8233
+ ctx.fillStyle = summarySelected || isHeaderColumnSelected || isColumnRangeSelected ? theme.selectionBackgroundColor : style?.backgroundColor ?? theme.headerBackgroundColor;
8134
8234
  ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
8135
- drawGridRect(ctx, rect, theme);
8235
+ drawGridRect(ctx, rect, theme, style?.borderColor, style?.borderWidth);
8136
8236
  const resolvedDisplayValue = resolveSummaryCellDisplayValue(
8137
8237
  column,
8138
8238
  summaryValues?.get(column.key),
@@ -8143,10 +8243,10 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
8143
8243
  ctx.beginPath();
8144
8244
  ctx.rect(cellClip.x, cellClip.y, cellClip.width, cellClip.height);
8145
8245
  ctx.clip();
8146
- ctx.fillStyle = theme.headerTextColor;
8147
- ctx.font = `600 ${theme.fontSize}px ${theme.fontFamily}`;
8246
+ ctx.fillStyle = style?.color ?? theme.headerTextColor;
8247
+ ctx.font = `${style?.fontWeight ?? "600"} ${fontSize}px ${style?.fontFamily ?? theme.fontFamily}`;
8148
8248
  ctx.textBaseline = "middle";
8149
- const align = column.align ?? "left";
8249
+ const align = style?.textAlign ?? column.align ?? "left";
8150
8250
  ctx.textAlign = align;
8151
8251
  const contentInsetStart = column.key === inlineContentInset?.columnKey ? inlineContentInset.width : 0;
8152
8252
  const contentRect = {
@@ -8159,16 +8259,16 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
8159
8259
  rect: contentRect,
8160
8260
  visibleRect,
8161
8261
  align,
8162
- padding: 12
8262
+ padding: paddingInline
8163
8263
  });
8164
8264
  const displayText = resolveSummaryDisplayText(ctx, {
8165
8265
  text: resolvedDisplayValue,
8166
8266
  visibleRect,
8167
- padding: 12
8267
+ padding: paddingInline
8168
8268
  });
8169
8269
  const textWidth = ctx.measureText(displayText).width;
8170
8270
  const textOriginX = textX - (align === "right" ? textWidth : align === "center" ? textWidth / 2 : 0);
8171
- const textTop = rect.y + (rect.height - theme.fontSize) / 2;
8271
+ const textTop = textY - fontSize / 2;
8172
8272
  const fragmentKey = `summary:${column.key}`;
8173
8273
  drawSelectableTextSelectionBackground({
8174
8274
  ctx,
@@ -8176,14 +8276,14 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
8176
8276
  textSelection,
8177
8277
  textOriginX,
8178
8278
  textTop,
8179
- textHeight: theme.fontSize,
8279
+ textHeight: fontSize,
8180
8280
  rowIndex: Number.MAX_SAFE_INTEGER,
8181
8281
  columnKey: column.key,
8182
8282
  contentIndex: 0,
8183
8283
  fragmentKey,
8184
8284
  color: theme.textSelectionBackgroundColor ?? "#99c2ff"
8185
8285
  });
8186
- ctx.fillText(displayText, textX, rect.y + rect.height / 2);
8286
+ ctx.fillText(displayText, textX, textY);
8187
8287
  textDescriptor = {
8188
8288
  rowIndex: Number.MAX_SAFE_INTEGER,
8189
8289
  contentIndex: 0,
@@ -8196,7 +8296,7 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
8196
8296
  x: textOriginX,
8197
8297
  y: textTop,
8198
8298
  width: textWidth,
8199
- height: theme.fontSize
8299
+ height: fontSize
8200
8300
  },
8201
8301
  cellClip
8202
8302
  ) ?? void 0,
@@ -10957,6 +11057,25 @@ function normalizeCellContents(contents) {
10957
11057
  }
10958
11058
  return [normalizeCellContentItem(contents)];
10959
11059
  }
11060
+ function applyCellTextStyle(contents, column) {
11061
+ const { color, fontSize, fontWeight, fontFamily } = column.cellStyle ?? {};
11062
+ if (color == null && fontSize == null && fontWeight == null && fontFamily == null)
11063
+ return contents;
11064
+ return contents.map((content) => ({
11065
+ ...content,
11066
+ style: {
11067
+ ...color != null ? { color } : {},
11068
+ ...fontSize != null ? { fontSize } : {},
11069
+ ...fontWeight != null ? { fontWeight } : {},
11070
+ ...fontFamily != null ? { fontFamily } : {},
11071
+ ..."color" in content && content.color != null ? { color: content.color } : {},
11072
+ ..."textColor" in content && content.textColor != null ? { color: content.textColor } : {},
11073
+ ..."fontSize" in content && content.fontSize != null ? { fontSize: content.fontSize } : {},
11074
+ ..."fontWeight" in content && content.fontWeight != null ? { fontWeight: content.fontWeight } : {},
11075
+ ...content.style
11076
+ }
11077
+ }));
11078
+ }
10960
11079
  function normalizeDrawableCellContents(contents) {
10961
11080
  return contents.filter(
10962
11081
  (content) => content.visible !== false && content.style?.display !== "none"
@@ -11130,7 +11249,10 @@ function drawBodyCellContents(params) {
11130
11249
  skipNestedTableOuterBorders,
11131
11250
  defaultRowHeight
11132
11251
  } = params;
11133
- const contents = normalizeDrawableCellContents(params.contents);
11252
+ const contents = applyCellTextStyle(
11253
+ normalizeDrawableCellContents(params.contents),
11254
+ column
11255
+ );
11134
11256
  if (contents.length === 0) {
11135
11257
  return void 0;
11136
11258
  }
@@ -11365,7 +11487,10 @@ function appendClippedContentDescriptors(descriptors, itemDescriptors, visibleRe
11365
11487
  }
11366
11488
  function measureBodyCellContentsHeight(params) {
11367
11489
  const { ctx, column, theme } = params;
11368
- const contents = normalizeDrawableCellContents(params.contents);
11490
+ const contents = applyCellTextStyle(
11491
+ normalizeDrawableCellContents(params.contents),
11492
+ column
11493
+ );
11369
11494
  if (contents.length === 0) {
11370
11495
  return 0;
11371
11496
  }
@@ -11395,7 +11520,10 @@ function measureBodyCellContentsHeight(params) {
11395
11520
  }
11396
11521
  function measureBodyCellContentsWidth(params) {
11397
11522
  const { ctx, column, theme } = params;
11398
- const contents = normalizeDrawableCellContents(params.contents);
11523
+ const contents = applyCellTextStyle(
11524
+ normalizeDrawableCellContents(params.contents),
11525
+ column
11526
+ );
11399
11527
  if (contents.length === 0) {
11400
11528
  return 0;
11401
11529
  }
@@ -20324,7 +20452,9 @@ var ListTableEventController = class {
20324
20452
  event.clientX,
20325
20453
  event.clientY
20326
20454
  );
20327
- const result = this.host.resolvePointerHit(position.x, position.y);
20455
+ const result = this.host.resolvePointerHit(position.x, position.y, {
20456
+ excludeKinds: ["resize-handle"]
20457
+ });
20328
20458
  const rawContextResult = typeof result.hitRowIndex === "number" ? { ...result, rowIndex: result.hitRowIndex } : result;
20329
20459
  const bodyRows = this.resolveBodyRows();
20330
20460
  const contextResult = hydrateBodyContentHitResult({
@@ -24286,13 +24416,22 @@ function drawSegmentRows(params, segment, columns, startRowIndex, endRowIndex, r
24286
24416
  collapseConfig: params.collapseConfig
24287
24417
  }) : [];
24288
24418
  const cellDescriptorStartIndex = params.descriptors.length;
24419
+ const activeStyle = isSelected || isSelectedCellRange ? params.theme.activeCellStyle : isRangeHighlighted ? params.theme.activeRowStyle : void 0;
24420
+ const styledColumn = activeStyle ? {
24421
+ ...cell.column,
24422
+ cellStyle: { ...cell.column.cellStyle, ...activeStyle }
24423
+ } : cell.column;
24424
+ const cellTheme = activeStyle?.backgroundColor ? {
24425
+ ...params.theme,
24426
+ selectionBackgroundColor: activeStyle.backgroundColor
24427
+ } : params.theme;
24289
24428
  const cellTooltip = drawBodyCell(
24290
24429
  ctx,
24291
24430
  rect,
24292
24431
  cell.record,
24293
24432
  cell.sourceRowIndex,
24294
- cell.column,
24295
- params.theme,
24433
+ styledColumn,
24434
+ cellTheme,
24296
24435
  params.rowBackgroundColor,
24297
24436
  params.striped === true,
24298
24437
  isHovered,
@@ -24339,11 +24478,12 @@ function drawSegmentRows(params, segment, columns, startRowIndex, endRowIndex, r
24339
24478
  }
24340
24479
  ctx.restore();
24341
24480
  }
24342
- function drawActiveCellBorder(ctx, rect) {
24343
- const inset = 0.5;
24481
+ function drawActiveCellBorder(ctx, rect, borderColor = ACTIVE_CELL_BORDER_COLOR, borderWidth = 1) {
24482
+ if (borderWidth <= 0) return;
24483
+ const inset = borderWidth / 2;
24344
24484
  ctx.save();
24345
- ctx.strokeStyle = ACTIVE_CELL_BORDER_COLOR;
24346
- ctx.lineWidth = 1;
24485
+ ctx.strokeStyle = borderColor;
24486
+ ctx.lineWidth = borderWidth;
24347
24487
  ctx.strokeRect(
24348
24488
  rect.x + inset,
24349
24489
  rect.y + inset,
@@ -25011,7 +25151,13 @@ function drawBodyCell(ctx, rect, record, rowIndex, column, theme, rowBackgroundC
25011
25151
  validationMessage
25012
25152
  );
25013
25153
  }
25014
- drawGridRect(ctx, rect, theme, theme.borderColor);
25154
+ drawGridRect(
25155
+ ctx,
25156
+ rect,
25157
+ theme,
25158
+ column.cellStyle?.borderColor ?? theme.borderColor,
25159
+ column.cellStyle?.borderWidth
25160
+ );
25015
25161
  ctx.restore();
25016
25162
  return validationMessage ? {
25017
25163
  text: validationMessage,
@@ -28524,6 +28670,7 @@ function renderListTablePagination(params) {
28524
28670
  return;
28525
28671
  }
28526
28672
  const paginationConfig = {
28673
+ styles: options.styles?.pagination,
28527
28674
  mode: paginationOptions.mode,
28528
28675
  current: state.currentPage,
28529
28676
  total: getPaginationTotal(options, total),
@@ -29271,6 +29418,7 @@ function drawActiveCellOverlay(params) {
29271
29418
  return;
29272
29419
  }
29273
29420
  const { ctx, layout } = params;
29421
+ if (params.borderWidth === 0) return;
29274
29422
  if (layout.rangeSegments?.length) {
29275
29423
  layout.rangeSegments.forEach((segment) => {
29276
29424
  ctx.save();
@@ -29282,8 +29430,8 @@ function drawActiveCellOverlay(params) {
29282
29430
  segment.clipRect.height
29283
29431
  );
29284
29432
  ctx.clip();
29285
- ctx.strokeStyle = "#1677ff";
29286
- ctx.lineWidth = 1;
29433
+ ctx.strokeStyle = params.borderColor ?? "#1677ff";
29434
+ ctx.lineWidth = params.borderWidth ?? 1;
29287
29435
  ctx.beginPath();
29288
29436
  ctx.moveTo(segment.startX, segment.startY);
29289
29437
  if (segment.controlX != null && segment.controlY != null) {
@@ -29305,7 +29453,13 @@ function drawActiveCellOverlay(params) {
29305
29453
  ctx.beginPath();
29306
29454
  ctx.rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
29307
29455
  ctx.clip();
29308
- drawRangeHighlightBorder(ctx, rect, { omitLeft, omitRight });
29456
+ drawRangeHighlightBorder(
29457
+ ctx,
29458
+ rect,
29459
+ { omitLeft, omitRight },
29460
+ params.borderColor,
29461
+ params.borderWidth
29462
+ );
29309
29463
  ctx.restore();
29310
29464
  });
29311
29465
  }
@@ -29319,7 +29473,12 @@ function drawActiveCellOverlay(params) {
29319
29473
  layout.clipRect.height
29320
29474
  );
29321
29475
  ctx.clip();
29322
- drawActiveCellBorder(ctx, layout.rect);
29476
+ drawActiveCellBorder(
29477
+ ctx,
29478
+ layout.rect,
29479
+ params.borderColor,
29480
+ params.borderWidth
29481
+ );
29323
29482
  ctx.restore();
29324
29483
  }
29325
29484
  }
@@ -29417,10 +29576,7 @@ function removeRangeSegmentsAtSharedLayerBoundaries(segments, ranges) {
29417
29576
  return;
29418
29577
  }
29419
29578
  const top = Math.max(left.y, right.y);
29420
- const bottom = Math.min(
29421
- left.y + left.height,
29422
- right.y + right.height
29423
- );
29579
+ const bottom = Math.min(left.y + left.height, right.y + right.height);
29424
29580
  if (bottom > top) {
29425
29581
  sharedBoundaries.push({ x: boundary, top, bottom });
29426
29582
  }
@@ -29610,10 +29766,10 @@ function subtractCoveredIntervals(start, end, coveredIntervals) {
29610
29766
  ([currentStart, currentEnd]) => currentEnd > currentStart
29611
29767
  );
29612
29768
  }
29613
- function drawRangeHighlightBorder(ctx, rect, edges = {}) {
29769
+ function drawRangeHighlightBorder(ctx, rect, edges = {}, borderColor = "#1677ff", borderWidth = 1) {
29614
29770
  ctx.save();
29615
- ctx.strokeStyle = "#1677ff";
29616
- ctx.lineWidth = 1;
29771
+ ctx.strokeStyle = borderColor;
29772
+ ctx.lineWidth = borderWidth;
29617
29773
  const left = rect.x + 0.5;
29618
29774
  const top = rect.y + 0.5;
29619
29775
  const right = rect.x + Math.max(rect.width - 0.5, 0);
@@ -29909,6 +30065,8 @@ function executeListTableRenderPipeline(params) {
29909
30065
  );
29910
30066
  drawActiveCellOverlay({
29911
30067
  ctx,
30068
+ borderColor: theme.activeCellStyle?.borderColor,
30069
+ borderWidth: theme.activeCellStyle?.borderWidth,
29912
30070
  layout: resolveActiveCellOverlayLayout({
29913
30071
  descriptors,
29914
30072
  selection,
@@ -30353,9 +30511,10 @@ var ListTableRenderController = class {
30353
30511
  const availableHeight = this.options.getContainerClientHeight() > 0 ? this.options.getContainerClientHeight() : hostSize.height;
30354
30512
  const zoom = this.resolveZoom();
30355
30513
  const layoutWidth = hostSize.width / zoom;
30356
- const layoutAvailableHeight = availableHeight / zoom;
30357
- const currentSnapshot = this.currentRenderSnapshot;
30358
- const measureSnapshot = currentSnapshot && currentSnapshot.width === layoutWidth && currentSnapshot.groupingBarHeight === (this.options.getGroupBarVisible?.() ? currentSnapshot.rowHeight : 0) && currentSnapshot.groupingColumns.map((column) => column.key).join("") === (this.options.getGroupColumnKeys?.() ?? []).join("") ? currentSnapshot : this.buildSnapshot(layoutWidth, layoutAvailableHeight, false);
30514
+ const measureSnapshot = this.buildSnapshot(
30515
+ layoutWidth,
30516
+ hostSize.height / zoom
30517
+ );
30359
30518
  if (!measureSnapshot) {
30360
30519
  this.options.setFittedHeight(null);
30361
30520
  return;
@@ -30374,10 +30533,13 @@ var ListTableRenderController = class {
30374
30533
  summaryHeight: measureSnapshot.bodyLayout.summaryHeight
30375
30534
  });
30376
30535
  const paginationElement = this.options.getPaginationElement();
30536
+ const scrollbar = this.options.getOptions().scrollbar;
30537
+ const horizontal = utils.resolveCanvasScrollbarAxis(scrollbar, "horizontal");
30538
+ const horizontalReserve = horizontal.visible && measureSnapshot.columnMetrics.centerContentWidth - measureSnapshot.columnMetrics.availableCenterWidth > 1 ? horizontal.thickness + Math.max(scrollbar?.horizontalBottom ?? 0, 0) : 0;
30377
30539
  const paginationHeight = paginationElement && paginationElement.style.display !== "none" ? paginationElement.offsetHeight : 0;
30378
30540
  const fittedHeight = resolveFittedTableHeight({
30379
30541
  availableHeight,
30380
- contentHeight: contentHeight * zoom + paginationHeight
30542
+ contentHeight: (contentHeight + horizontalReserve) * zoom + paginationHeight
30381
30543
  });
30382
30544
  this.options.setFittedHeight(
30383
30545
  fittedHeight == null ? null : fittedHeight + TABLE_CONTENT_BORDER_SIZE
@@ -30663,6 +30825,7 @@ function resolvePaginationSignature(params) {
30663
30825
  paginationConfig ? "enabled" : "disabled",
30664
30826
  paginationConfig?.mode ?? "",
30665
30827
  paginationConfig?.total ?? params.total,
30828
+ JSON.stringify(params.options.styles?.pagination ?? null),
30666
30829
  params.total > 0 ? "nonempty" : "empty",
30667
30830
  params.currentPage,
30668
30831
  params.pageSize,
@@ -32568,6 +32731,7 @@ var ListTableCore = class {
32568
32731
  /** 由 assembleListTableCoreControllers 在构造阶段挂载。 */
32569
32732
  __publicField(this, "renderController");
32570
32733
  __publicField(this, "debugManager");
32734
+ options = resolveListTableStyleOptions(options);
32571
32735
  this.container = container;
32572
32736
  this.options = options;
32573
32737
  applyInitialColumnVisibility(options.columns);
@@ -32622,6 +32786,7 @@ var ListTableCore = class {
32622
32786
  * @param options 新配置。
32623
32787
  */
32624
32788
  updateOptions(options) {
32789
+ options = resolveListTableStyleOptions(options);
32625
32790
  this.animationController.stopCarouselScroll();
32626
32791
  const host = this.asAssemblyHost();
32627
32792
  const shouldResetColumnConfig = shouldPersistIncomingColumnConfig(