@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/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { stringifyDataIndex, getValueByDataIndex, clamp, copyTextSync, copyText, exportTableToXlsx, resolveCanvasScrollbarAxis, formatPreciseNumber, addPreciseNumbers, comparePreciseNumbers, isSameDataIndex, dividePreciseNumber, exportTableToTxt, exportTableToCsv, downloadJsonFile, mapRowsToExportRecords, copyJson, copyRows, parseNumberValue, formatNumberValue, formatPercentValue, formatScientificValue, formatChineseNumber, parseChineseNumber, normalizeDecimalPlaces, roundPreciseNumber, isDateTimeFormatPattern, formatDateTimeValue, formatCustomNumberPattern, isPointInRect as isPointInRect$1 } from '@canvas-components/utils';
1
+ import { stringifyDataIndex, getValueByDataIndex, clamp, resolveCanvasScrollbarAxis, copyTextSync, copyText, exportTableToXlsx, formatPreciseNumber, addPreciseNumbers, comparePreciseNumbers, isSameDataIndex, dividePreciseNumber, exportTableToTxt, exportTableToCsv, downloadJsonFile, mapRowsToExportRecords, copyJson, copyRows, parseNumberValue, formatNumberValue, formatPercentValue, formatScientificValue, formatChineseNumber, parseChineseNumber, normalizeDecimalPlaces, roundPreciseNumber, isDateTimeFormatPattern, formatDateTimeValue, formatCustomNumberPattern, isPointInRect as isPointInRect$1 } from '@canvas-components/utils';
2
2
  import { drawBarcodeToCanvas } from '@canvas-components/barcode';
3
3
  import { drawCanvasChartToCanvas, getCanvasChartRenderer, resolveCanvasChartTooltipText } from '@canvas-components/chart';
4
4
  import { drawQrCodeToCanvas } from '@canvas-components/qrcode';
@@ -69,6 +69,87 @@ var DebugManager = class {
69
69
  console.info(`[ListTable Debug] ${label}`, payload);
70
70
  }
71
71
  };
72
+
73
+ // src/services/table-styles-service.ts
74
+ function resolveStylePixels(value) {
75
+ if (typeof value === "string" && !/^\s*\d+(?:\.\d+)?(?:px)?\s*$/.test(value))
76
+ return void 0;
77
+ const number = typeof value === "string" ? parseFloat(value) : value;
78
+ return number != null && Number.isFinite(number) && number >= 0 ? number : void 0;
79
+ }
80
+ function resolveCanvasCellStyle(style) {
81
+ if (!style) return void 0;
82
+ const padding = typeof style.padding === "string" ? style.padding.trim().split(/\s+/) : [style.padding];
83
+ const result = {
84
+ backgroundColor: style.backgroundColor,
85
+ color: style.color,
86
+ fontSize: resolveStylePixels(style.fontSize),
87
+ fontWeight: style.fontWeight == null ? void 0 : String(style.fontWeight),
88
+ fontFamily: style.fontFamily,
89
+ textAlign: style.textAlign,
90
+ verticalAlign: style.verticalAlign,
91
+ paddingInline: resolveStylePixels(style.paddingInline) ?? (padding.length <= 2 ? resolveStylePixels(padding[1] ?? padding[0]) : void 0),
92
+ paddingBlock: resolveStylePixels(style.paddingBlock) ?? (padding.length <= 2 ? resolveStylePixels(padding[0]) : void 0),
93
+ borderColor: style.borderColor,
94
+ borderWidth: resolveStylePixels(style.borderWidth)
95
+ };
96
+ return Object.fromEntries(
97
+ Object.entries(result).filter(([, value]) => value !== void 0)
98
+ );
99
+ }
100
+ function resolveListTableStyleOptions(options) {
101
+ const styles = options.styles;
102
+ if (!styles) return options;
103
+ const cell = resolveCanvasCellStyle(styles.cell) ?? {};
104
+ const header = { ...cell, ...resolveCanvasCellStyle(styles.header) };
105
+ const body = { ...cell, ...resolveCanvasCellStyle(styles.body) };
106
+ const summary = { ...cell, ...resolveCanvasCellStyle(styles.summary) };
107
+ const mapColumns = (columns) => columns.map((column) => ({
108
+ ...column,
109
+ align: column.align ?? (column.cellStyle?.textAlign ?? body.textAlign),
110
+ headerAlign: column.headerAlign ?? (column.headerStyle?.textAlign ?? column.align ?? header.textAlign),
111
+ cellStyle: { ...body, ...column.cellStyle },
112
+ headerStyle: { ...header, ...column.headerStyle },
113
+ summaryStyle: { ...summary, ...column.summaryStyle },
114
+ children: column.children ? mapColumns(column.children) : void 0
115
+ }));
116
+ const scrollbar = { ...options.scrollbar };
117
+ for (const axis of ["vertical", "horizontal"]) {
118
+ const style = axis === "vertical" ? styles.scrollVertical : styles.scrollHorizontal;
119
+ if (!style || scrollbar[axis] === false) continue;
120
+ const mapped = {
121
+ thumbColor: style.color,
122
+ trackColor: style.backgroundColor,
123
+ thickness: resolveStylePixels(
124
+ axis === "vertical" ? style.width : style.height
125
+ ),
126
+ thumbRadius: resolveStylePixels(style.borderRadius)
127
+ };
128
+ scrollbar[axis] = {
129
+ ...scrollbar[axis],
130
+ ...Object.fromEntries(
131
+ Object.entries(mapped).filter(([, value]) => value !== void 0)
132
+ )
133
+ };
134
+ }
135
+ return {
136
+ ...options,
137
+ columns: mapColumns(options.columns),
138
+ scrollbar,
139
+ theme: {
140
+ ...options.theme,
141
+ ...cell.borderColor ? { borderColor: cell.borderColor } : {},
142
+ ...cell.fontSize != null ? { fontSize: cell.fontSize } : {},
143
+ ...cell.fontFamily ? { fontFamily: cell.fontFamily } : {},
144
+ ...body.color ? { textColor: body.color } : {},
145
+ ...header.backgroundColor ? { headerBackgroundColor: header.backgroundColor } : {},
146
+ ...header.color ? { headerTextColor: header.color } : {},
147
+ ...body.backgroundColor ? { backgroundColor: body.backgroundColor } : {},
148
+ activeCellStyle: resolveCanvasCellStyle(styles.activeCell),
149
+ activeRowStyle: resolveCanvasCellStyle(styles.activeRow)
150
+ }
151
+ };
152
+ }
72
153
  function resolveColumnKey(column) {
73
154
  return column.key?.trim() || stringifyDataIndex(column.dataIndex);
74
155
  }
@@ -583,15 +664,19 @@ function stretchColumnWidths(columns, containerWidth) {
583
664
  }
584
665
  const extra = containerWidth - totalWidth;
585
666
  const stretchableWidth = computeColumnWidths(stretchableColumns);
586
- const ratio = stretchableWidth > 0 ? extra / stretchableWidth : 0;
587
- for (const column of stretchableColumns) {
588
- column.width = Math.round(column.width * (1 + ratio));
589
- }
590
- const adjustedTotal = computeColumnWidths(columns);
591
- const remain = containerWidth - adjustedTotal;
592
- if (remain > 0) {
593
- stretchableColumns[stretchableColumns.length - 1].width += remain;
594
- }
667
+ let accumulatedWidth = 0;
668
+ let allocatedExtra = 0;
669
+ stretchableColumns.forEach((column, index) => {
670
+ accumulatedWidth += column.width;
671
+ const targetExtra = index === stretchableColumns.length - 1 ? extra : Math.min(
672
+ extra,
673
+ Math.floor(
674
+ extra * (stretchableWidth > 0 ? accumulatedWidth / stretchableWidth : (index + 1) / stretchableColumns.length)
675
+ )
676
+ );
677
+ column.width += targetExtra - allocatedExtra;
678
+ allocatedExtra = targetExtra;
679
+ });
595
680
  }
596
681
  function shrinkColumnWidthsToFit(columns, containerWidth) {
597
682
  let remaining = Math.max(
@@ -691,6 +776,7 @@ function normalizeColumn(column, depth, parentKey) {
691
776
  moneyFormat: column.moneyFormat,
692
777
  dataFormat: column.dataFormat,
693
778
  headerStyle: column.headerStyle,
779
+ summaryStyle: column.summaryStyle,
694
780
  summary: column.summary,
695
781
  summaryTitle: column.summaryTitle,
696
782
  meta: column.meta,
@@ -7201,10 +7287,11 @@ function roundRectPath(ctx, x, y, width, height, radius) {
7201
7287
  }
7202
7288
 
7203
7289
  // src/rendering/primitives/draw-grid.ts
7204
- function drawGridRect(ctx, rect, theme, borderColor = theme.borderColor) {
7290
+ function drawGridRect(ctx, rect, theme, borderColor = theme.borderColor, borderWidth = 1) {
7291
+ if (borderWidth <= 0) return;
7205
7292
  ctx.save();
7206
7293
  ctx.strokeStyle = borderColor;
7207
- ctx.lineWidth = 1;
7294
+ ctx.lineWidth = borderWidth;
7208
7295
  ctx.beginPath();
7209
7296
  const showTop = rect.y > 0;
7210
7297
  const showLeft = rect.x > 0;
@@ -7236,7 +7323,8 @@ function resolveHeaderTextLayout(params) {
7236
7323
  allowActions,
7237
7324
  hasFilter,
7238
7325
  contentInsetStart = 0,
7239
- contentInsetEnd = 0
7326
+ contentInsetEnd = 0,
7327
+ paddingInline = HEADER_TEXT_PADDING
7240
7328
  } = params;
7241
7329
  const contentRect = {
7242
7330
  x: rect.x + contentInsetStart,
@@ -7258,11 +7346,11 @@ function resolveHeaderTextLayout(params) {
7258
7346
  contentRect,
7259
7347
  contentVisibleRect,
7260
7348
  align,
7261
- HEADER_TEXT_PADDING
7349
+ paddingInline
7262
7350
  );
7263
7351
  const baseLayout = {
7264
7352
  align,
7265
- maxWidth: Math.max(contentVisibleRect.width - HEADER_TEXT_PADDING * 2, 12),
7353
+ maxWidth: Math.max(contentVisibleRect.width - paddingInline * 2, 12),
7266
7354
  x: baseX
7267
7355
  };
7268
7356
  if (!allowActions || !actionVisibilityState.visible || align === "left") {
@@ -7274,10 +7362,10 @@ function resolveHeaderTextLayout(params) {
7274
7362
  trailingInset: contentInsetEnd
7275
7363
  });
7276
7364
  const textRight = Math.min(
7277
- contentVisibleRect.x + contentVisibleRect.width - HEADER_TEXT_PADDING,
7278
- actionLayout.startX - HEADER_TEXT_PADDING
7365
+ contentVisibleRect.x + contentVisibleRect.width - paddingInline,
7366
+ actionLayout.startX - paddingInline
7279
7367
  );
7280
- const textLeft = contentVisibleRect.x + HEADER_TEXT_PADDING;
7368
+ const textLeft = contentVisibleRect.x + paddingInline;
7281
7369
  if (align === "center") {
7282
7370
  const centeredWidth = Math.max(
7283
7371
  Math.min(baseX - textLeft, textRight - baseX) * 2,
@@ -7412,9 +7500,15 @@ function drawHeaderCell(params, cell, clipRect) {
7412
7500
  const isRangeSelected = isHeaderCellInRange(params.rangeHighlight, cell);
7413
7501
  ctx.fillStyle = isSelected || isRangeSelected ? theme.selectionBackgroundColor : cell.node.style?.backgroundColor ?? theme.headerBackgroundColor;
7414
7502
  ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
7415
- drawGridRect(ctx, rect, theme);
7503
+ drawGridRect(
7504
+ ctx,
7505
+ rect,
7506
+ theme,
7507
+ cell.node.style?.borderColor,
7508
+ cell.node.style?.borderWidth
7509
+ );
7416
7510
  ctx.fillStyle = cell.node.style?.color ?? theme.headerTextColor;
7417
- ctx.font = `${theme.headerFontWeight} ${theme.fontSize}px ${theme.fontFamily}`;
7511
+ ctx.font = `${cell.node.style?.fontWeight ?? theme.headerFontWeight} ${cell.node.style?.fontSize ?? theme.fontSize}px ${cell.node.style?.fontFamily ?? theme.fontFamily}`;
7418
7512
  ctx.textBaseline = "middle";
7419
7513
  const visibleRect = clipRect ? intersectRects(rect, clipRect) : rect;
7420
7514
  if (!visibleRect) {
@@ -7446,6 +7540,7 @@ function drawHeaderCell(params, cell, clipRect) {
7446
7540
  allowActions: cell.node.children.length === 0,
7447
7541
  hasFilter: params.filterableColumnKeys.has(cell.node.key),
7448
7542
  contentWidth: measureHeaderContentWidth(ctx, titleContent),
7543
+ paddingInline: cell.node.style?.paddingInline,
7449
7544
  contentInsetStart: resolveHeaderContentInsetStart({
7450
7545
  columnKey: cell.node.key,
7451
7546
  hasChildren: cell.node.children.length > 0,
@@ -7457,7 +7552,7 @@ function drawHeaderCell(params, cell, clipRect) {
7457
7552
  const textY = resolveHeaderContentCenterY(
7458
7553
  rect,
7459
7554
  titleContent,
7460
- theme.fontSize,
7555
+ cell.node.style?.fontSize ?? theme.fontSize,
7461
7556
  cell.node.style?.paddingBlock ?? params.defaultPaddingBlock ?? resolveDensityPaddingBlock(cell.height),
7462
7557
  cell.node.style?.verticalAlign
7463
7558
  );
@@ -8119,6 +8214,11 @@ function drawSummarySegment(params, columns, clipRect, defaultTitleColumnKey) {
8119
8214
  function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeaderKey, summarySelected, rangeHighlight, clipRect, descriptors, inlineContentInset, defaultTitleColumnKey, textSelection) {
8120
8215
  ctx.save();
8121
8216
  const cellClip = clipRect ? intersectRects2(rect, clipRect) : rect;
8217
+ const style = column.summaryStyle;
8218
+ const fontSize = style?.fontSize ?? theme.fontSize;
8219
+ const paddingInline = style?.paddingInline ?? 12;
8220
+ const paddingBlock = style?.paddingBlock ?? 0;
8221
+ 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;
8122
8222
  if (!cellClip) {
8123
8223
  ctx.restore();
8124
8224
  return;
@@ -8128,9 +8228,9 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
8128
8228
  column.leafIndex,
8129
8229
  (rangeHighlight ?? EMPTY_RANGE_HIGHLIGHT2).selectedColumnRange
8130
8230
  );
8131
- ctx.fillStyle = summarySelected || isHeaderColumnSelected || isColumnRangeSelected ? theme.selectionBackgroundColor : theme.headerBackgroundColor;
8231
+ ctx.fillStyle = summarySelected || isHeaderColumnSelected || isColumnRangeSelected ? theme.selectionBackgroundColor : style?.backgroundColor ?? theme.headerBackgroundColor;
8132
8232
  ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
8133
- drawGridRect(ctx, rect, theme);
8233
+ drawGridRect(ctx, rect, theme, style?.borderColor, style?.borderWidth);
8134
8234
  const resolvedDisplayValue = resolveSummaryCellDisplayValue(
8135
8235
  column,
8136
8236
  summaryValues?.get(column.key),
@@ -8141,10 +8241,10 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
8141
8241
  ctx.beginPath();
8142
8242
  ctx.rect(cellClip.x, cellClip.y, cellClip.width, cellClip.height);
8143
8243
  ctx.clip();
8144
- ctx.fillStyle = theme.headerTextColor;
8145
- ctx.font = `600 ${theme.fontSize}px ${theme.fontFamily}`;
8244
+ ctx.fillStyle = style?.color ?? theme.headerTextColor;
8245
+ ctx.font = `${style?.fontWeight ?? "600"} ${fontSize}px ${style?.fontFamily ?? theme.fontFamily}`;
8146
8246
  ctx.textBaseline = "middle";
8147
- const align = column.align ?? "left";
8247
+ const align = style?.textAlign ?? column.align ?? "left";
8148
8248
  ctx.textAlign = align;
8149
8249
  const contentInsetStart = column.key === inlineContentInset?.columnKey ? inlineContentInset.width : 0;
8150
8250
  const contentRect = {
@@ -8157,16 +8257,16 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
8157
8257
  rect: contentRect,
8158
8258
  visibleRect,
8159
8259
  align,
8160
- padding: 12
8260
+ padding: paddingInline
8161
8261
  });
8162
8262
  const displayText = resolveSummaryDisplayText(ctx, {
8163
8263
  text: resolvedDisplayValue,
8164
8264
  visibleRect,
8165
- padding: 12
8265
+ padding: paddingInline
8166
8266
  });
8167
8267
  const textWidth = ctx.measureText(displayText).width;
8168
8268
  const textOriginX = textX - (align === "right" ? textWidth : align === "center" ? textWidth / 2 : 0);
8169
- const textTop = rect.y + (rect.height - theme.fontSize) / 2;
8269
+ const textTop = textY - fontSize / 2;
8170
8270
  const fragmentKey = `summary:${column.key}`;
8171
8271
  drawSelectableTextSelectionBackground({
8172
8272
  ctx,
@@ -8174,14 +8274,14 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
8174
8274
  textSelection,
8175
8275
  textOriginX,
8176
8276
  textTop,
8177
- textHeight: theme.fontSize,
8277
+ textHeight: fontSize,
8178
8278
  rowIndex: Number.MAX_SAFE_INTEGER,
8179
8279
  columnKey: column.key,
8180
8280
  contentIndex: 0,
8181
8281
  fragmentKey,
8182
8282
  color: theme.textSelectionBackgroundColor ?? "#99c2ff"
8183
8283
  });
8184
- ctx.fillText(displayText, textX, rect.y + rect.height / 2);
8284
+ ctx.fillText(displayText, textX, textY);
8185
8285
  textDescriptor = {
8186
8286
  rowIndex: Number.MAX_SAFE_INTEGER,
8187
8287
  contentIndex: 0,
@@ -8194,7 +8294,7 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
8194
8294
  x: textOriginX,
8195
8295
  y: textTop,
8196
8296
  width: textWidth,
8197
- height: theme.fontSize
8297
+ height: fontSize
8198
8298
  },
8199
8299
  cellClip
8200
8300
  ) ?? void 0,
@@ -10955,6 +11055,25 @@ function normalizeCellContents(contents) {
10955
11055
  }
10956
11056
  return [normalizeCellContentItem(contents)];
10957
11057
  }
11058
+ function applyCellTextStyle(contents, column) {
11059
+ const { color, fontSize, fontWeight, fontFamily } = column.cellStyle ?? {};
11060
+ if (color == null && fontSize == null && fontWeight == null && fontFamily == null)
11061
+ return contents;
11062
+ return contents.map((content) => ({
11063
+ ...content,
11064
+ style: {
11065
+ ...color != null ? { color } : {},
11066
+ ...fontSize != null ? { fontSize } : {},
11067
+ ...fontWeight != null ? { fontWeight } : {},
11068
+ ...fontFamily != null ? { fontFamily } : {},
11069
+ ..."color" in content && content.color != null ? { color: content.color } : {},
11070
+ ..."textColor" in content && content.textColor != null ? { color: content.textColor } : {},
11071
+ ..."fontSize" in content && content.fontSize != null ? { fontSize: content.fontSize } : {},
11072
+ ..."fontWeight" in content && content.fontWeight != null ? { fontWeight: content.fontWeight } : {},
11073
+ ...content.style
11074
+ }
11075
+ }));
11076
+ }
10958
11077
  function normalizeDrawableCellContents(contents) {
10959
11078
  return contents.filter(
10960
11079
  (content) => content.visible !== false && content.style?.display !== "none"
@@ -11128,7 +11247,10 @@ function drawBodyCellContents(params) {
11128
11247
  skipNestedTableOuterBorders,
11129
11248
  defaultRowHeight
11130
11249
  } = params;
11131
- const contents = normalizeDrawableCellContents(params.contents);
11250
+ const contents = applyCellTextStyle(
11251
+ normalizeDrawableCellContents(params.contents),
11252
+ column
11253
+ );
11132
11254
  if (contents.length === 0) {
11133
11255
  return void 0;
11134
11256
  }
@@ -11363,7 +11485,10 @@ function appendClippedContentDescriptors(descriptors, itemDescriptors, visibleRe
11363
11485
  }
11364
11486
  function measureBodyCellContentsHeight(params) {
11365
11487
  const { ctx, column, theme } = params;
11366
- const contents = normalizeDrawableCellContents(params.contents);
11488
+ const contents = applyCellTextStyle(
11489
+ normalizeDrawableCellContents(params.contents),
11490
+ column
11491
+ );
11367
11492
  if (contents.length === 0) {
11368
11493
  return 0;
11369
11494
  }
@@ -11393,7 +11518,10 @@ function measureBodyCellContentsHeight(params) {
11393
11518
  }
11394
11519
  function measureBodyCellContentsWidth(params) {
11395
11520
  const { ctx, column, theme } = params;
11396
- const contents = normalizeDrawableCellContents(params.contents);
11521
+ const contents = applyCellTextStyle(
11522
+ normalizeDrawableCellContents(params.contents),
11523
+ column
11524
+ );
11397
11525
  if (contents.length === 0) {
11398
11526
  return 0;
11399
11527
  }
@@ -20322,7 +20450,9 @@ var ListTableEventController = class {
20322
20450
  event.clientX,
20323
20451
  event.clientY
20324
20452
  );
20325
- const result = this.host.resolvePointerHit(position.x, position.y);
20453
+ const result = this.host.resolvePointerHit(position.x, position.y, {
20454
+ excludeKinds: ["resize-handle"]
20455
+ });
20326
20456
  const rawContextResult = typeof result.hitRowIndex === "number" ? { ...result, rowIndex: result.hitRowIndex } : result;
20327
20457
  const bodyRows = this.resolveBodyRows();
20328
20458
  const contextResult = hydrateBodyContentHitResult({
@@ -24284,13 +24414,22 @@ function drawSegmentRows(params, segment, columns, startRowIndex, endRowIndex, r
24284
24414
  collapseConfig: params.collapseConfig
24285
24415
  }) : [];
24286
24416
  const cellDescriptorStartIndex = params.descriptors.length;
24417
+ const activeStyle = isSelected || isSelectedCellRange ? params.theme.activeCellStyle : isRangeHighlighted ? params.theme.activeRowStyle : void 0;
24418
+ const styledColumn = activeStyle ? {
24419
+ ...cell.column,
24420
+ cellStyle: { ...cell.column.cellStyle, ...activeStyle }
24421
+ } : cell.column;
24422
+ const cellTheme = activeStyle?.backgroundColor ? {
24423
+ ...params.theme,
24424
+ selectionBackgroundColor: activeStyle.backgroundColor
24425
+ } : params.theme;
24287
24426
  const cellTooltip = drawBodyCell(
24288
24427
  ctx,
24289
24428
  rect,
24290
24429
  cell.record,
24291
24430
  cell.sourceRowIndex,
24292
- cell.column,
24293
- params.theme,
24431
+ styledColumn,
24432
+ cellTheme,
24294
24433
  params.rowBackgroundColor,
24295
24434
  params.striped === true,
24296
24435
  isHovered,
@@ -24337,11 +24476,12 @@ function drawSegmentRows(params, segment, columns, startRowIndex, endRowIndex, r
24337
24476
  }
24338
24477
  ctx.restore();
24339
24478
  }
24340
- function drawActiveCellBorder(ctx, rect) {
24341
- const inset = 0.5;
24479
+ function drawActiveCellBorder(ctx, rect, borderColor = ACTIVE_CELL_BORDER_COLOR, borderWidth = 1) {
24480
+ if (borderWidth <= 0) return;
24481
+ const inset = borderWidth / 2;
24342
24482
  ctx.save();
24343
- ctx.strokeStyle = ACTIVE_CELL_BORDER_COLOR;
24344
- ctx.lineWidth = 1;
24483
+ ctx.strokeStyle = borderColor;
24484
+ ctx.lineWidth = borderWidth;
24345
24485
  ctx.strokeRect(
24346
24486
  rect.x + inset,
24347
24487
  rect.y + inset,
@@ -25009,7 +25149,13 @@ function drawBodyCell(ctx, rect, record, rowIndex, column, theme, rowBackgroundC
25009
25149
  validationMessage
25010
25150
  );
25011
25151
  }
25012
- drawGridRect(ctx, rect, theme, theme.borderColor);
25152
+ drawGridRect(
25153
+ ctx,
25154
+ rect,
25155
+ theme,
25156
+ column.cellStyle?.borderColor ?? theme.borderColor,
25157
+ column.cellStyle?.borderWidth
25158
+ );
25013
25159
  ctx.restore();
25014
25160
  return validationMessage ? {
25015
25161
  text: validationMessage,
@@ -28522,6 +28668,7 @@ function renderListTablePagination(params) {
28522
28668
  return;
28523
28669
  }
28524
28670
  const paginationConfig = {
28671
+ styles: options.styles?.pagination,
28525
28672
  mode: paginationOptions.mode,
28526
28673
  current: state.currentPage,
28527
28674
  total: getPaginationTotal(options, total),
@@ -29269,6 +29416,7 @@ function drawActiveCellOverlay(params) {
29269
29416
  return;
29270
29417
  }
29271
29418
  const { ctx, layout } = params;
29419
+ if (params.borderWidth === 0) return;
29272
29420
  if (layout.rangeSegments?.length) {
29273
29421
  layout.rangeSegments.forEach((segment) => {
29274
29422
  ctx.save();
@@ -29280,8 +29428,8 @@ function drawActiveCellOverlay(params) {
29280
29428
  segment.clipRect.height
29281
29429
  );
29282
29430
  ctx.clip();
29283
- ctx.strokeStyle = "#1677ff";
29284
- ctx.lineWidth = 1;
29431
+ ctx.strokeStyle = params.borderColor ?? "#1677ff";
29432
+ ctx.lineWidth = params.borderWidth ?? 1;
29285
29433
  ctx.beginPath();
29286
29434
  ctx.moveTo(segment.startX, segment.startY);
29287
29435
  if (segment.controlX != null && segment.controlY != null) {
@@ -29303,7 +29451,13 @@ function drawActiveCellOverlay(params) {
29303
29451
  ctx.beginPath();
29304
29452
  ctx.rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
29305
29453
  ctx.clip();
29306
- drawRangeHighlightBorder(ctx, rect, { omitLeft, omitRight });
29454
+ drawRangeHighlightBorder(
29455
+ ctx,
29456
+ rect,
29457
+ { omitLeft, omitRight },
29458
+ params.borderColor,
29459
+ params.borderWidth
29460
+ );
29307
29461
  ctx.restore();
29308
29462
  });
29309
29463
  }
@@ -29317,7 +29471,12 @@ function drawActiveCellOverlay(params) {
29317
29471
  layout.clipRect.height
29318
29472
  );
29319
29473
  ctx.clip();
29320
- drawActiveCellBorder(ctx, layout.rect);
29474
+ drawActiveCellBorder(
29475
+ ctx,
29476
+ layout.rect,
29477
+ params.borderColor,
29478
+ params.borderWidth
29479
+ );
29321
29480
  ctx.restore();
29322
29481
  }
29323
29482
  }
@@ -29415,10 +29574,7 @@ function removeRangeSegmentsAtSharedLayerBoundaries(segments, ranges) {
29415
29574
  return;
29416
29575
  }
29417
29576
  const top = Math.max(left.y, right.y);
29418
- const bottom = Math.min(
29419
- left.y + left.height,
29420
- right.y + right.height
29421
- );
29577
+ const bottom = Math.min(left.y + left.height, right.y + right.height);
29422
29578
  if (bottom > top) {
29423
29579
  sharedBoundaries.push({ x: boundary, top, bottom });
29424
29580
  }
@@ -29608,10 +29764,10 @@ function subtractCoveredIntervals(start, end, coveredIntervals) {
29608
29764
  ([currentStart, currentEnd]) => currentEnd > currentStart
29609
29765
  );
29610
29766
  }
29611
- function drawRangeHighlightBorder(ctx, rect, edges = {}) {
29767
+ function drawRangeHighlightBorder(ctx, rect, edges = {}, borderColor = "#1677ff", borderWidth = 1) {
29612
29768
  ctx.save();
29613
- ctx.strokeStyle = "#1677ff";
29614
- ctx.lineWidth = 1;
29769
+ ctx.strokeStyle = borderColor;
29770
+ ctx.lineWidth = borderWidth;
29615
29771
  const left = rect.x + 0.5;
29616
29772
  const top = rect.y + 0.5;
29617
29773
  const right = rect.x + Math.max(rect.width - 0.5, 0);
@@ -29907,6 +30063,8 @@ function executeListTableRenderPipeline(params) {
29907
30063
  );
29908
30064
  drawActiveCellOverlay({
29909
30065
  ctx,
30066
+ borderColor: theme.activeCellStyle?.borderColor,
30067
+ borderWidth: theme.activeCellStyle?.borderWidth,
29910
30068
  layout: resolveActiveCellOverlayLayout({
29911
30069
  descriptors,
29912
30070
  selection,
@@ -30351,9 +30509,10 @@ var ListTableRenderController = class {
30351
30509
  const availableHeight = this.options.getContainerClientHeight() > 0 ? this.options.getContainerClientHeight() : hostSize.height;
30352
30510
  const zoom = this.resolveZoom();
30353
30511
  const layoutWidth = hostSize.width / zoom;
30354
- const layoutAvailableHeight = availableHeight / zoom;
30355
- const currentSnapshot = this.currentRenderSnapshot;
30356
- 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);
30512
+ const measureSnapshot = this.buildSnapshot(
30513
+ layoutWidth,
30514
+ hostSize.height / zoom
30515
+ );
30357
30516
  if (!measureSnapshot) {
30358
30517
  this.options.setFittedHeight(null);
30359
30518
  return;
@@ -30372,10 +30531,13 @@ var ListTableRenderController = class {
30372
30531
  summaryHeight: measureSnapshot.bodyLayout.summaryHeight
30373
30532
  });
30374
30533
  const paginationElement = this.options.getPaginationElement();
30534
+ const scrollbar = this.options.getOptions().scrollbar;
30535
+ const horizontal = resolveCanvasScrollbarAxis(scrollbar, "horizontal");
30536
+ const horizontalReserve = horizontal.visible && measureSnapshot.columnMetrics.centerContentWidth - measureSnapshot.columnMetrics.availableCenterWidth > 1 ? horizontal.thickness + Math.max(scrollbar?.horizontalBottom ?? 0, 0) : 0;
30375
30537
  const paginationHeight = paginationElement && paginationElement.style.display !== "none" ? paginationElement.offsetHeight : 0;
30376
30538
  const fittedHeight = resolveFittedTableHeight({
30377
30539
  availableHeight,
30378
- contentHeight: contentHeight * zoom + paginationHeight
30540
+ contentHeight: (contentHeight + horizontalReserve) * zoom + paginationHeight
30379
30541
  });
30380
30542
  this.options.setFittedHeight(
30381
30543
  fittedHeight == null ? null : fittedHeight + TABLE_CONTENT_BORDER_SIZE
@@ -30661,6 +30823,7 @@ function resolvePaginationSignature(params) {
30661
30823
  paginationConfig ? "enabled" : "disabled",
30662
30824
  paginationConfig?.mode ?? "",
30663
30825
  paginationConfig?.total ?? params.total,
30826
+ JSON.stringify(params.options.styles?.pagination ?? null),
30664
30827
  params.total > 0 ? "nonempty" : "empty",
30665
30828
  params.currentPage,
30666
30829
  params.pageSize,
@@ -32566,6 +32729,7 @@ var ListTableCore = class {
32566
32729
  /** 由 assembleListTableCoreControllers 在构造阶段挂载。 */
32567
32730
  __publicField(this, "renderController");
32568
32731
  __publicField(this, "debugManager");
32732
+ options = resolveListTableStyleOptions(options);
32569
32733
  this.container = container;
32570
32734
  this.options = options;
32571
32735
  applyInitialColumnVisibility(options.columns);
@@ -32620,6 +32784,7 @@ var ListTableCore = class {
32620
32784
  * @param options 新配置。
32621
32785
  */
32622
32786
  updateOptions(options) {
32787
+ options = resolveListTableStyleOptions(options);
32623
32788
  this.animationController.stopCarouselScroll();
32624
32789
  const host = this.asAssemblyHost();
32625
32790
  const shouldResetColumnConfig = shouldPersistIncomingColumnConfig(