@canvas-components/list-table 0.3.25 → 0.3.27

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, 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';
1
+ import { stringifyDataIndex, getValueByDataIndex, clamp, resolveCanvasScrollbarAxis, copyTextSync, copyText, resolveCanvasScrollbarHoldSpeed, exportTableToXlsx, formatPreciseNumber, addPreciseNumbers, comparePreciseNumbers, isSameDataIndex, dividePreciseNumber, exportTableToTxt, exportTableToCsv, mapRowsToExportRecords, downloadJsonFile, 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, resolveCanvasChartOption, getCanvasChartRenderer, resolveCanvasChartTooltipText } from '@canvas-components/chart';
4
4
  import * as antDesignIcons from '@ant-design/icons-svg';
@@ -1036,6 +1036,11 @@ function getNextRightFixedInsertIndex(columns) {
1036
1036
  }
1037
1037
 
1038
1038
  // src/features/header-settings/header-settings-feature.ts
1039
+ function haveVisibleLeafColumnsChanged(previous, next) {
1040
+ if (previous.length !== next.length) return true;
1041
+ const previousKeys = new Set(previous.map((column) => column.key));
1042
+ return next.some((column) => !previousKeys.has(column.key));
1043
+ }
1039
1044
  function cloneColumns(columns) {
1040
1045
  return columns.map((column) => ({
1041
1046
  ...column,
@@ -1162,6 +1167,7 @@ function saveHeaderSettingsColumn(columns, draft) {
1162
1167
  existing.minWidth = minWidth;
1163
1168
  existing.maxWidth = maxWidth;
1164
1169
  if (draft.order != null) moveColumnToOrder(siblings, existing, draft.order);
1170
+ draft.key = resolveColumnKey(existing);
1165
1171
  return null;
1166
1172
  }
1167
1173
  const dataIndex = draft.dataIndex?.trim();
@@ -1187,6 +1193,7 @@ function saveHeaderSettingsColumn(columns, draft) {
1187
1193
  } else if (!existing) {
1188
1194
  siblings.splice((draft.order ?? maxOrder) - 1, 0, column);
1189
1195
  }
1196
+ draft.key = resolveColumnKey(column);
1190
1197
  return null;
1191
1198
  }
1192
1199
  function findSiblingColumnsByKey(columns, key) {
@@ -1284,6 +1291,9 @@ function toggleHeaderColumnVisibility(params) {
1284
1291
  };
1285
1292
  }
1286
1293
  function resolveCollapsedHeaderColumnMarkers(params) {
1294
+ if (params.showCollapsedColumnIcon === false) {
1295
+ return [];
1296
+ }
1287
1297
  ensureColumnKeysInPlace(params.columns);
1288
1298
  const allLeafKeys = collectLeafColumnKeys(params.columns);
1289
1299
  const excludedKeySet = new Set(params.excludedColumnKeys ?? []);
@@ -1460,6 +1470,7 @@ function buildHeaderSettingsItem(column, totalVisibleLeafCount, parentHidden, or
1460
1470
  minWidth: column.minWidth,
1461
1471
  maxWidth: column.maxWidth,
1462
1472
  fixed: column.fixed,
1473
+ sortable: !column.children?.length && column.allowSort !== false && column.sorter !== false,
1463
1474
  order,
1464
1475
  siblingCount,
1465
1476
  checked,
@@ -1620,6 +1631,23 @@ function applyThemeVariables(wrapper, theme) {
1620
1631
  );
1621
1632
  }
1622
1633
 
1634
+ // src/interaction/pointer.ts
1635
+ function getCanvasPointerPosition(canvas, clientX, clientY) {
1636
+ const rect = canvas.getBoundingClientRect();
1637
+ const scale = getElementViewportScale(canvas, rect);
1638
+ return {
1639
+ x: (clientX - rect.left) / scale.x,
1640
+ y: (clientY - rect.top) / scale.y
1641
+ };
1642
+ }
1643
+ function getElementViewportScale(element, rect = element.getBoundingClientRect()) {
1644
+ const resolveScale = (viewportSize, layoutSize) => layoutSize > 0 && Math.abs(viewportSize - layoutSize) >= 1 ? viewportSize / layoutSize : 1;
1645
+ return {
1646
+ x: resolveScale(rect.width, element.clientWidth),
1647
+ y: resolveScale(rect.height, element.clientHeight)
1648
+ };
1649
+ }
1650
+
1623
1651
  // src/adapters/dom-host.ts
1624
1652
  var RESIZE_RENDER_SETTLE_DELAY = 240;
1625
1653
  var ListTableDomHost = class {
@@ -1789,23 +1817,27 @@ var ListTableDomHost = class {
1789
1817
  return this.nodes;
1790
1818
  }
1791
1819
  toViewportPoint(x, y) {
1792
- const hostRect = this.nodes?.canvasHostElement.getBoundingClientRect();
1793
- if (!hostRect) {
1820
+ const hostElement = this.nodes?.canvasHostElement;
1821
+ const hostRect = hostElement?.getBoundingClientRect();
1822
+ if (!hostElement || !hostRect) {
1794
1823
  return { x, y };
1795
1824
  }
1825
+ const scale = getElementViewportScale(hostElement, hostRect);
1796
1826
  return {
1797
- x: hostRect.left + x * this.contentZoom,
1798
- y: hostRect.top + y * this.contentZoom
1827
+ x: hostRect.left + x * this.contentZoom * scale.x,
1828
+ y: hostRect.top + y * this.contentZoom * scale.y
1799
1829
  };
1800
1830
  }
1801
1831
  toViewportRect(rect) {
1802
1832
  const point = this.toViewportPoint(rect.x, rect.y);
1833
+ const hostElement = this.nodes?.canvasHostElement;
1834
+ const scale = hostElement ? getElementViewportScale(hostElement) : { x: 1, y: 1 };
1803
1835
  return {
1804
1836
  ...rect,
1805
1837
  x: point.x,
1806
1838
  y: point.y,
1807
- width: rect.width * this.contentZoom,
1808
- height: rect.height * this.contentZoom
1839
+ width: rect.width * this.contentZoom * scale.x,
1840
+ height: rect.height * this.contentZoom * scale.y
1809
1841
  };
1810
1842
  }
1811
1843
  getCanvasViewportRect() {
@@ -1859,15 +1891,6 @@ var ListTableDomHost = class {
1859
1891
  }
1860
1892
  };
1861
1893
 
1862
- // src/interaction/pointer.ts
1863
- function getCanvasPointerPosition(canvas, clientX, clientY) {
1864
- const rect = canvas.getBoundingClientRect();
1865
- return {
1866
- x: clientX - rect.left,
1867
- y: clientY - rect.top
1868
- };
1869
- }
1870
-
1871
1894
  // src/adapters/canvas-host.ts
1872
1895
  var ListTableCanvasHost = class {
1873
1896
  constructor() {
@@ -3276,14 +3299,17 @@ function mapKindToArea(kind, actionType) {
3276
3299
  }
3277
3300
  function getPriority(descriptor) {
3278
3301
  let priority = getBasePriority(descriptor.kind);
3302
+ if (descriptor.debugNodeType === "header-edit-icon" || descriptor.debugNodeType === "nested-table-header-edit-icon") {
3303
+ priority += 1;
3304
+ }
3279
3305
  if (descriptor.kind === "summary" && descriptor.columnKey) {
3280
3306
  priority += 1;
3281
3307
  }
3282
3308
  if ((descriptor.kind === "body" || descriptor.kind === "body-content" || descriptor.kind === "body-control") && descriptor.frozen) {
3283
3309
  priority += 2;
3284
3310
  }
3285
- if (descriptor.kind === "body" && descriptor.fixed) {
3286
- priority += 1;
3311
+ if ((descriptor.kind === "body" || descriptor.kind === "body-content" || descriptor.kind === "body-control") && descriptor.fixed) {
3312
+ priority += 2;
3287
3313
  }
3288
3314
  if (isHeaderDescriptor(descriptor.kind) && descriptor.fixed) {
3289
3315
  priority += 3;
@@ -3303,6 +3329,9 @@ function getBasePriority(kind) {
3303
3329
  return 2;
3304
3330
  case "resize-handle":
3305
3331
  return 4;
3332
+ // 折叠列图标覆盖列宽热区,但仍低于固定列表头的遮挡层(优先级 5)。
3333
+ case "column-collapse-trigger":
3334
+ return 4.5;
3306
3335
  case "header-action":
3307
3336
  return 3;
3308
3337
  case "header-selection":
@@ -3315,7 +3344,6 @@ function getBasePriority(kind) {
3315
3344
  return 2;
3316
3345
  case "expand-trigger":
3317
3346
  case "collapse-trigger":
3318
- case "column-collapse-trigger":
3319
3347
  return 3;
3320
3348
  case "expanded-row":
3321
3349
  case "body":
@@ -3474,6 +3502,60 @@ function applyListTableRenderPassResult(params) {
3474
3502
  params.setScrollPageSize(projection.scrollPageSize);
3475
3503
  }
3476
3504
 
3505
+ // src/rendering/cell-content/text-measure-cache.ts
3506
+ var MAX_ENTRIES = 2048;
3507
+ var MAX_TEXT_LENGTH = 512;
3508
+ var fontRevisions = /* @__PURE__ */ new WeakMap();
3509
+ var contextCaches = /* @__PURE__ */ new WeakMap();
3510
+ function measureCachedText(ctx, text) {
3511
+ const fonts = ctx.canvas?.ownerDocument?.fonts;
3512
+ let fontRevision = 0;
3513
+ if (fonts) {
3514
+ let revision = fontRevisions.get(fonts);
3515
+ if (!revision) {
3516
+ revision = { value: 0 };
3517
+ fontRevisions.set(fonts, revision);
3518
+ const invalidate = () => {
3519
+ revision.value += 1;
3520
+ };
3521
+ fonts.addEventListener("loadingdone", invalidate);
3522
+ fonts.addEventListener("loadingerror", invalidate);
3523
+ }
3524
+ fontRevision = revision.value;
3525
+ if (fonts.status === "loading") {
3526
+ contextCaches.delete(ctx);
3527
+ return ctx.measureText(text);
3528
+ }
3529
+ }
3530
+ if (text.length > MAX_TEXT_LENGTH) return ctx.measureText(text);
3531
+ let cache = contextCaches.get(ctx);
3532
+ if (!cache || cache.fontRevision !== fontRevision) {
3533
+ cache = { fontRevision, entries: /* @__PURE__ */ new Map() };
3534
+ contextCaches.set(ctx, cache);
3535
+ }
3536
+ const key = JSON.stringify([
3537
+ ctx.font,
3538
+ ctx.textAlign,
3539
+ ctx.textBaseline,
3540
+ ctx.direction,
3541
+ ctx.fontKerning,
3542
+ ctx.fontStretch,
3543
+ ctx.fontVariantCaps,
3544
+ ctx.letterSpacing,
3545
+ ctx.wordSpacing,
3546
+ ctx.textRendering,
3547
+ text
3548
+ ]);
3549
+ const cached = cache.entries.get(key);
3550
+ if (cached) return cached;
3551
+ const metrics = ctx.measureText(text);
3552
+ if (cache.entries.size >= MAX_ENTRIES) {
3553
+ cache.entries.delete(cache.entries.keys().next().value);
3554
+ }
3555
+ cache.entries.set(key, metrics);
3556
+ return metrics;
3557
+ }
3558
+
3477
3559
  // src/rendering/cell-content/content-style.ts
3478
3560
  function resolveContentFontSize(content, fallbackFontSize) {
3479
3561
  return content.style?.fontSize ?? content.fontSize ?? fallbackFontSize;
@@ -3534,7 +3616,7 @@ function buildCanvasFont(params) {
3534
3616
  return `${fontWeight} ${fontSize}px ${fontFamily}`.trim();
3535
3617
  }
3536
3618
  function measureTextBounds(ctx, text) {
3537
- const metrics = ctx.measureText(text);
3619
+ const metrics = measureCachedText(ctx, text);
3538
3620
  const ascent = metrics.actualBoundingBoxAscent || 0;
3539
3621
  const descent = metrics.actualBoundingBoxDescent || 0;
3540
3622
  const width = metrics.width;
@@ -5189,11 +5271,41 @@ function drawHeaderActionGlyph(ctx, rect, actionType, color = "#8c8c8c", sortOrd
5189
5271
  ctx.fill();
5190
5272
  } else if (actionType === "filter") {
5191
5273
  drawFilterIcon(ctx, rect);
5192
- } else {
5274
+ } else if (actionType === "fixed") {
5193
5275
  drawFixedPinIcon(ctx, rect);
5276
+ } else {
5277
+ drawEditIcon(ctx, rect);
5194
5278
  }
5195
5279
  ctx.restore();
5196
5280
  }
5281
+ function drawEditIcon(ctx, rect) {
5282
+ const scale = Math.min(rect.width, rect.height) / 14;
5283
+ const x = rect.x + (rect.width - 14 * scale) / 2;
5284
+ const y = rect.y + (rect.height - 14 * scale) / 2;
5285
+ ctx.save();
5286
+ ctx.translate(x, y);
5287
+ ctx.scale(scale, scale);
5288
+ ctx.beginPath();
5289
+ ctx.moveTo(1.5, 10.15);
5290
+ ctx.lineTo(9.4, 2.25);
5291
+ ctx.lineTo(11.75, 4.6);
5292
+ ctx.lineTo(3.85, 12.5);
5293
+ ctx.lineTo(1.3, 12.7);
5294
+ ctx.closePath();
5295
+ ctx.fill();
5296
+ ctx.beginPath();
5297
+ ctx.moveTo(10.05, 1.6);
5298
+ ctx.lineTo(10.7, 0.95);
5299
+ ctx.lineTo(11.4, 0.6);
5300
+ ctx.lineTo(12.1, 0.95);
5301
+ ctx.lineTo(13.05, 1.9);
5302
+ ctx.lineTo(13.4, 2.6);
5303
+ ctx.lineTo(13.05, 3.3);
5304
+ ctx.lineTo(12.4, 3.95);
5305
+ ctx.closePath();
5306
+ ctx.fill();
5307
+ ctx.restore();
5308
+ }
5197
5309
  function drawFilterIcon(ctx, rect) {
5198
5310
  const iconWidth = rect.width * 0.92;
5199
5311
  const iconHeight = rect.height * 0.7;
@@ -7444,6 +7556,19 @@ function sortRows(rows, sortState, leafColumns) {
7444
7556
  return 0;
7445
7557
  });
7446
7558
  }
7559
+ async function sortRowsAsync(params) {
7560
+ const { rows, signal } = params;
7561
+ const indices = await sortRowIndicesAsync(params);
7562
+ if (!indices) {
7563
+ return rows;
7564
+ }
7565
+ return materializeRows({
7566
+ rows,
7567
+ indices,
7568
+ signal,
7569
+ abortMessage: "sort rows aborted"
7570
+ });
7571
+ }
7447
7572
  async function sortRowIndicesAsync(params) {
7448
7573
  let rowIndices = params.rowIndices ?? null;
7449
7574
  const sorters = orderSortingState(params.sortState);
@@ -7687,6 +7812,21 @@ async function mapToSourceRowIndices(params) {
7687
7812
  recordQueryStageDuration(params.trace, "indexMapping", mappingStartedAt);
7688
7813
  return result;
7689
7814
  }
7815
+ async function materializeRows(params) {
7816
+ const { rows, indices, signal, abortMessage } = params;
7817
+ const result = Array(indices.length);
7818
+ let sliceStartedAt = getTaskNow();
7819
+ for (let index = 0; index < indices.length; index += 1) {
7820
+ throwIfTaskAborted(signal, abortMessage);
7821
+ result[index] = rows[indices[index]];
7822
+ if ((index + 1) % ASYNC_QUERY_SLICE_ITEM_LIMIT === 0 || (index + 1) % 256 === 0 && isTaskSliceExpired(sliceStartedAt)) {
7823
+ await yieldToMainThread();
7824
+ throwIfTaskAborted(signal, abortMessage);
7825
+ sliceStartedAt = getTaskNow();
7826
+ }
7827
+ }
7828
+ return result;
7829
+ }
7690
7830
  function isAbortError(error) {
7691
7831
  return error instanceof Error && error.name === "AbortError";
7692
7832
  }
@@ -8079,12 +8219,17 @@ function toQueryFilters(filters) {
8079
8219
  );
8080
8220
  }
8081
8221
  function toQuerySorter(sortState, leafColumns) {
8082
- return orderSortingState(sortState).map((item) => ({
8083
- columnKey: item.key,
8084
- field: leafColumns.find((column) => column.key === item.key)?.dataIndex,
8085
- order: item.order,
8086
- priority: item.priority
8087
- }));
8222
+ return orderSortingState(sortState).map((item) => {
8223
+ const column = leafColumns.find((candidate) => candidate.key === item.key);
8224
+ const animation = typeof column?.sorter === "object" ? column.sorter.animation : void 0;
8225
+ return {
8226
+ columnKey: item.key,
8227
+ field: column?.dataIndex,
8228
+ order: item.order,
8229
+ priority: item.priority,
8230
+ ...animation === void 0 ? {} : { animation }
8231
+ };
8232
+ });
8088
8233
  }
8089
8234
  function getActiveFilterColumnKeys(filters) {
8090
8235
  return Object.entries(filters).filter(([, value]) => isMeaningfulFilterValue(value)).map(([columnKey]) => columnKey);
@@ -8457,6 +8602,7 @@ function resolveHeaderTextLayout(params) {
8457
8602
  actionVisibilityState,
8458
8603
  allowActions,
8459
8604
  hasFilter,
8605
+ hasEdit = false,
8460
8606
  contentInsetStart = 0,
8461
8607
  contentInsetEnd = 0,
8462
8608
  paddingInline = HEADER_TEXT_PADDING
@@ -8488,14 +8634,23 @@ function resolveHeaderTextLayout(params) {
8488
8634
  maxWidth: Math.max(contentVisibleRect.width - paddingInline * 2, 12),
8489
8635
  x: baseX
8490
8636
  };
8491
- if (!allowActions || !actionVisibilityState.visible || align === "left") {
8637
+ if (!allowActions || !actionVisibilityState.visible) {
8492
8638
  return baseLayout;
8493
8639
  }
8494
8640
  const actionLayout = getHeaderActionLayout({
8495
8641
  rect,
8496
8642
  hasFilter,
8643
+ hasEdit,
8644
+ visibilityState: actionVisibilityState,
8497
8645
  trailingInset: contentInsetEnd
8498
8646
  });
8647
+ if (align === "left") {
8648
+ if (!hasEdit) return baseLayout;
8649
+ return {
8650
+ ...baseLayout,
8651
+ maxWidth: Math.max(actionLayout.startX - baseX - paddingInline, 0)
8652
+ };
8653
+ }
8499
8654
  const textRight = Math.min(
8500
8655
  contentVisibleRect.x + contentVisibleRect.width - paddingInline,
8501
8656
  actionLayout.startX - paddingInline
@@ -8526,11 +8681,14 @@ function resolveHeaderTextLayout(params) {
8526
8681
  };
8527
8682
  }
8528
8683
  function getHeaderActionLayout(params) {
8529
- const actionTypes = ["sort"];
8530
- if (params.hasFilter) {
8531
- actionTypes.push("filter");
8532
- }
8533
- actionTypes.push("fixed");
8684
+ const editOnly = params.hasEdit && params.visibilityState != null && !params.visibilityState.hovered && !params.visibilityState.sorted && !params.visibilityState.filtered && !params.visibilityState.fixed;
8685
+ const actionTypes = [];
8686
+ if (!editOnly) {
8687
+ actionTypes.push("sort");
8688
+ if (params.hasFilter) actionTypes.push("filter");
8689
+ actionTypes.push("fixed");
8690
+ }
8691
+ if (params.hasEdit) actionTypes.push("edit");
8534
8692
  const totalWidth = ACTION_SIZE * actionTypes.length + ACTION_GAP * Math.max(actionTypes.length - 1, 0);
8535
8693
  return {
8536
8694
  actionTypes,
@@ -8581,6 +8739,9 @@ function drawHeaderLayer(params, layer) {
8581
8739
  if (cell.layer !== layer) {
8582
8740
  return;
8583
8741
  }
8742
+ if (layer === "center" && centerClipRect && (cell.x + cell.width < centerClipRect.x - 1 || cell.x > centerClipRect.x + centerClipRect.width + 1)) {
8743
+ return;
8744
+ }
8584
8745
  if (layer === "center" && centerClipRect) {
8585
8746
  params.ctx.save();
8586
8747
  params.ctx.beginPath();
@@ -8626,7 +8787,11 @@ function drawHeaderCell(params, cell, clipRect) {
8626
8787
  };
8627
8788
  ctx.save();
8628
8789
  const isSelected = isHeaderCellSelected(params, cell.node.key, rect);
8629
- const isRangeSelected = isHeaderCellInRange(params.rangeHighlight, cell);
8790
+ const isRangeSelected = isHeaderCellInRange(
8791
+ params.rangeHighlight,
8792
+ cell,
8793
+ params.leafColumnKeys
8794
+ );
8630
8795
  ctx.fillStyle = isSelected || isRangeSelected ? theme.selectionBackgroundColor : cell.node.style?.backgroundColor ?? theme.headerBackgroundColor;
8631
8796
  ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
8632
8797
  drawGridRect(
@@ -8650,13 +8815,15 @@ function drawHeaderCell(params, cell, clipRect) {
8650
8815
  );
8651
8816
  const isExpandSystemColumn = cell.node.children.length === 0 && cell.node.column.meta?.systemType === "expandable";
8652
8817
  const isRowSelectorSystemColumn = cell.node.children.length === 0 && cell.node.column.meta?.systemType === "rowSelector";
8818
+ const isEditableLeaf = cell.node.children.length === 0 && !!cell.node.column.editable;
8653
8819
  const visibleState = getHeaderActionVisibilityState(
8654
8820
  cell.node.key,
8655
8821
  params.hoveredColumnKey,
8656
8822
  params.sortState.find((item) => item.key === cell.node.key)?.key ?? null,
8657
8823
  params.filteredColumnKeys,
8658
8824
  params.filterableColumnKeys,
8659
- params.fixedColumnKeys
8825
+ params.fixedColumnKeys,
8826
+ isEditableLeaf
8660
8827
  );
8661
8828
  const titleContent = cell.node.titleContent ?? [
8662
8829
  { type: "text", text: cell.node.title }
@@ -8668,6 +8835,7 @@ function drawHeaderCell(params, cell, clipRect) {
8668
8835
  actionVisibilityState: visibleState,
8669
8836
  allowActions: cell.node.children.length === 0,
8670
8837
  hasFilter: params.filterableColumnKeys.has(cell.node.key),
8838
+ hasEdit: isEditableLeaf,
8671
8839
  contentWidth: measureHeaderContentWidth(ctx, titleContent),
8672
8840
  paddingInline: cell.node.style?.paddingInline,
8673
8841
  contentInsetStart: resolveHeaderContentInsetStart({
@@ -8791,7 +8959,9 @@ function drawHeaderCell(params, cell, clipRect) {
8791
8959
  cell.node.key,
8792
8960
  visibleState,
8793
8961
  cell.node.fixed,
8794
- visibleRect
8962
+ visibleRect,
8963
+ isEditableLeaf,
8964
+ isSelected || isRangeSelected
8795
8965
  );
8796
8966
  drawResizeHandles(params, rect, cell.node.key, cell.node.fixed);
8797
8967
  }
@@ -8827,11 +8997,11 @@ function resolveHeaderContentCenterY(rect, contents, fontSize, paddingBlock, ver
8827
8997
  function measureHeaderContentWidth(ctx, contents) {
8828
8998
  const gap = 4;
8829
8999
  return contents.reduce(
8830
- (sum, content) => sum + (content.type === "img" ? Math.max(content.width ?? content.height ?? 16, 1) : ctx.measureText(content.text).width),
9000
+ (sum, content) => sum + (content.type === "img" ? Math.max(content.width ?? content.height ?? 16, 1) : measureCachedText(ctx, content.text).width),
8831
9001
  0
8832
9002
  ) + Math.max(contents.length - 1, 0) * gap;
8833
9003
  }
8834
- function drawHeaderActions(params, rect, columnKey, visibilityState, fixed, visibleRect = rect) {
9004
+ function drawHeaderActions(params, rect, columnKey, visibilityState, fixed, visibleRect = rect, hasEdit = false, selected = false) {
8835
9005
  if (!visibilityState.visible) {
8836
9006
  return;
8837
9007
  }
@@ -8843,6 +9013,8 @@ function drawHeaderActions(params, rect, columnKey, visibilityState, fixed, visi
8843
9013
  const actionLayout = getHeaderActionLayout({
8844
9014
  rect,
8845
9015
  hasFilter: params.filterableColumnKeys.has(columnKey),
9016
+ hasEdit,
9017
+ visibilityState,
8846
9018
  trailingInset: resolveCollapsedColumnMarkerSet(
8847
9019
  params.collapsedColumnMarkers,
8848
9020
  columnKey
@@ -8850,7 +9022,7 @@ function drawHeaderActions(params, rect, columnKey, visibilityState, fixed, visi
8850
9022
  });
8851
9023
  const { actionTypes, startX, totalWidth } = actionLayout;
8852
9024
  const centerY = rect.y + rect.height / 2;
8853
- const headerSelected = isHeaderCellSelected(params, columnKey, rect);
9025
+ const headerSelected = selected || isHeaderCellSelected(params, columnKey, rect);
8854
9026
  ctx.save();
8855
9027
  ctx.fillStyle = headerSelected ? params.theme.selectionBackgroundColor : params.theme.headerBackgroundColor;
8856
9028
  ctx.beginPath();
@@ -8872,6 +9044,28 @@ function drawHeaderActions(params, rect, columnKey, visibilityState, fixed, visi
8872
9044
  width: ACTION_SIZE2,
8873
9045
  height: ACTION_SIZE2
8874
9046
  };
9047
+ if (actionType === "edit") {
9048
+ drawHeaderActionIcon(
9049
+ ctx,
9050
+ actionRect,
9051
+ "edit",
9052
+ true,
9053
+ false,
9054
+ headerSelected,
9055
+ params.theme.selectionBackgroundColor
9056
+ );
9057
+ const hitRect2 = intersectRects(actionRect, visibleRect);
9058
+ if (hitRect2)
9059
+ descriptors.push({
9060
+ kind: "header",
9061
+ rect: hitRect2,
9062
+ columnKey,
9063
+ fixed,
9064
+ debugNodeType: "header-edit-icon",
9065
+ debugText: "\u5F53\u524D\u5217\u53EF\u7F16\u8F91"
9066
+ });
9067
+ return;
9068
+ }
8875
9069
  const iconHovered = params.hoveredColumnKey === columnKey && params.hoveredActionType === (actionType === "sort" ? "sort-trigger" : actionType === "filter" ? "filter-trigger" : "fixed-trigger");
8876
9070
  drawHeaderActionIcon(
8877
9071
  ctx,
@@ -8950,11 +9144,16 @@ function isHeaderCellSelected(params, columnKey, rect) {
8950
9144
  }
8951
9145
  return isSameRect(params.selectedHeaderRect, rect);
8952
9146
  }
8953
- function isHeaderCellInRange(rangeHighlight, cell) {
8954
- const range = (rangeHighlight ?? EMPTY_RANGE_HIGHLIGHT).selectedColumnRange;
8955
- if (!range) {
8956
- return false;
9147
+ function isHeaderCellInRange(rangeHighlight, cell, leafColumnKeys) {
9148
+ const state = rangeHighlight ?? EMPTY_RANGE_HIGHLIGHT;
9149
+ if (state.selectedColumnKeys != null) {
9150
+ if (leafColumnKeys) {
9151
+ return leafColumnKeys.slice(cell.node.leafStartIndex, cell.node.leafEndIndex + 1).some((key) => state.selectedColumnKeys?.includes(key));
9152
+ }
9153
+ return state.selectedColumnKeys.includes(cell.node.key);
8957
9154
  }
9155
+ const range = state.selectedColumnRange;
9156
+ if (!range) return false;
8958
9157
  return cell.node.leafStartIndex <= range.end && cell.node.leafEndIndex >= range.start;
8959
9158
  }
8960
9159
  function isSameRect(left, right) {
@@ -9019,7 +9218,7 @@ function getHeaderSelectionRect(rect) {
9019
9218
  height: size
9020
9219
  };
9021
9220
  }
9022
- function getHeaderActionVisibilityState(columnKey, hoveredColumnKey, sortedColumnKey, filteredColumnKeys, filterableColumnKeys, fixedColumnKeys) {
9221
+ function getHeaderActionVisibilityState(columnKey, hoveredColumnKey, sortedColumnKey, filteredColumnKeys, filterableColumnKeys, fixedColumnKeys, editable) {
9023
9222
  const hovered = hoveredColumnKey === columnKey;
9024
9223
  const sorted = sortedColumnKey === columnKey;
9025
9224
  const filtered = filterableColumnKeys.has(columnKey) && filteredColumnKeys.has(columnKey);
@@ -9029,7 +9228,7 @@ function getHeaderActionVisibilityState(columnKey, hoveredColumnKey, sortedColum
9029
9228
  sorted,
9030
9229
  filtered,
9031
9230
  fixed,
9032
- visible: hovered || sorted || filtered || fixed
9231
+ visible: hovered || sorted || filtered || fixed || editable
9033
9232
  };
9034
9233
  }
9035
9234
  function getActionActive(actionType, visibilityState) {
@@ -9064,7 +9263,7 @@ function drawHeaderActionIcon(ctx, rect, actionType, active, hovered = false, se
9064
9263
  function drawHeaderContent(ctx, contents, x, y, maxWidth, align, requestRender) {
9065
9264
  const gap = 4;
9066
9265
  const widths = contents.map(
9067
- (content) => content.type === "img" ? Math.max(content.width ?? content.height ?? 16, 1) : ctx.measureText(content.text).width
9266
+ (content) => content.type === "img" ? Math.max(content.width ?? content.height ?? 16, 1) : measureCachedText(ctx, content.text).width
9068
9267
  );
9069
9268
  const totalWidth = widths.reduce((sum, width) => sum + width, 0) + Math.max(contents.length - 1, 0) * gap;
9070
9269
  const displayWidth = Math.min(totalWidth, Math.max(maxWidth, 0));
@@ -9089,19 +9288,19 @@ function drawHeaderContent(ctx, contents, x, y, maxWidth, align, requestRender)
9089
9288
  ctx.textAlign = "left";
9090
9289
  const text = ellipsisText(ctx, content.text, availableWidth);
9091
9290
  ctx.fillText(text, cursorX, y);
9092
- cursorX += Math.min(ctx.measureText(text).width, availableWidth) + gap;
9291
+ cursorX += Math.min(measureCachedText(ctx, text).width, availableWidth) + gap;
9093
9292
  ctx.restore();
9094
9293
  });
9095
9294
  }
9096
9295
  function ellipsisText(ctx, text, maxWidth) {
9097
- if (ctx.measureText(text).width <= maxWidth) {
9296
+ if (measureCachedText(ctx, text).width <= maxWidth) {
9098
9297
  return text;
9099
9298
  }
9100
9299
  const ellipsis = "...";
9101
9300
  let content = text;
9102
9301
  while (content.length > 0) {
9103
9302
  content = content.slice(0, -1);
9104
- const measured = ctx.measureText(`${content}${ellipsis}`).width;
9303
+ const measured = measureCachedText(ctx, `${content}${ellipsis}`).width;
9105
9304
  if (measured <= maxWidth) {
9106
9305
  return `${content}${ellipsis}`;
9107
9306
  }
@@ -9205,6 +9404,544 @@ function findCellByKey(headerRows, columnKey) {
9205
9404
  }
9206
9405
  return null;
9207
9406
  }
9407
+
9408
+ // src/services/range-highlight-service.ts
9409
+ var EMPTY_RANGE_HIGHLIGHT_STATE = {
9410
+ selectedRowAnchorIndex: null,
9411
+ selectedRowRange: null,
9412
+ selectedColumnAnchorKey: null,
9413
+ selectedColumnRange: null
9414
+ };
9415
+ function isIndexInHighlightRange(index, range) {
9416
+ return Boolean(range && index >= range.start && index <= range.end);
9417
+ }
9418
+ function isColumnInHighlight(state, columnKey, columnIndex) {
9419
+ return state.selectedColumnKeys != null ? state.selectedColumnKeys.includes(columnKey) : isIndexInHighlightRange(columnIndex, state.selectedColumnRange);
9420
+ }
9421
+ function isRowInHighlight(state, rowIndex) {
9422
+ const ranges = state.selectedRowRanges ?? (state.selectedRowRange ? [state.selectedRowRange] : []);
9423
+ return ranges.some((range) => isIndexInHighlightRange(rowIndex, range));
9424
+ }
9425
+ function isCellInHighlight(state, rowIndex, columnIndex) {
9426
+ const ranges = state.selectedCellRanges ?? (state.selectedCellRange ? [state.selectedCellRange] : []);
9427
+ return ranges.some(
9428
+ (range) => rowIndex >= range.startRowIndex && rowIndex <= range.endRowIndex && columnIndex >= range.startColumnIndex && columnIndex <= range.endColumnIndex
9429
+ );
9430
+ }
9431
+ function resolveRowHighlightForSelectorClick(params) {
9432
+ const rowIndex = Math.max(0, Math.floor(params.rowIndex));
9433
+ const base = {
9434
+ ...params.current,
9435
+ selectedColumnAnchorKey: null,
9436
+ selectedColumnRange: null,
9437
+ selectedColumnKeys: null,
9438
+ selectedCellRange: params.ctrlKey ? params.current.selectedCellRange ?? null : null,
9439
+ selectedCellRanges: params.ctrlKey ? params.current.selectedCellRanges ?? null : null,
9440
+ selectedCellAnchor: params.ctrlKey ? params.current.selectedCellAnchor ?? null : null
9441
+ };
9442
+ if (params.ctrlKey) {
9443
+ const ranges = params.current.selectedRowRanges ?? (params.current.selectedRowRange ? [params.current.selectedRowRange] : []);
9444
+ const nextRanges = ranges.flatMap((range) => {
9445
+ if (!isIndexInHighlightRange(rowIndex, range)) return [range];
9446
+ return [
9447
+ ...range.start < rowIndex ? [{ start: range.start, end: rowIndex - 1 }] : [],
9448
+ ...rowIndex < range.end ? [{ start: rowIndex + 1, end: range.end }] : []
9449
+ ];
9450
+ });
9451
+ if (!ranges.some((range) => isIndexInHighlightRange(rowIndex, range))) {
9452
+ nextRanges.push({ start: rowIndex, end: rowIndex });
9453
+ }
9454
+ nextRanges.sort((left, right) => left.start - right.start);
9455
+ return {
9456
+ ...base,
9457
+ selectedRowAnchorIndex: nextRanges.length ? isRowInHighlight(
9458
+ { selectedRowRange: null, selectedRowRanges: nextRanges },
9459
+ rowIndex
9460
+ ) ? rowIndex : nextRanges[nextRanges.length - 1].end : null,
9461
+ selectedRowRange: null,
9462
+ selectedRowRanges: nextRanges
9463
+ };
9464
+ }
9465
+ const anchor = params.shiftKey ? params.current.selectedRowAnchorIndex ?? rowIndex : rowIndex;
9466
+ return {
9467
+ ...base,
9468
+ selectedRowAnchorIndex: anchor,
9469
+ selectedRowRange: createHighlightRange(anchor, rowIndex),
9470
+ selectedRowRanges: null
9471
+ };
9472
+ }
9473
+ function resolveCellHighlightForClick(params) {
9474
+ const columnIndex = params.leafColumnKeys.indexOf(params.columnKey);
9475
+ if (columnIndex < 0) return params.current;
9476
+ const base = {
9477
+ ...params.current,
9478
+ selectedRowAnchorIndex: params.ctrlKey && params.preserveRowSelection ? params.current.selectedRowAnchorIndex : null,
9479
+ selectedRowRange: params.ctrlKey && params.preserveRowSelection ? params.current.selectedRowRange : null,
9480
+ selectedRowRanges: params.ctrlKey && params.preserveRowSelection ? params.current.selectedRowRanges ?? null : null,
9481
+ selectedColumnAnchorKey: null,
9482
+ selectedColumnRange: null,
9483
+ selectedColumnKeys: null
9484
+ };
9485
+ if (params.shiftKey && !params.ctrlKey) {
9486
+ const anchor = params.current.selectedCellAnchor ?? params.previousCell ?? {
9487
+ rowIndex: params.rowIndex,
9488
+ columnKey: params.columnKey
9489
+ };
9490
+ const anchorColumnIndex = params.leafColumnKeys.indexOf(anchor.columnKey);
9491
+ return {
9492
+ ...base,
9493
+ selectedCellAnchor: anchor,
9494
+ selectedCellRange: {
9495
+ startRowIndex: Math.min(anchor.rowIndex, params.rowIndex),
9496
+ endRowIndex: Math.max(anchor.rowIndex, params.rowIndex),
9497
+ startColumnIndex: Math.min(
9498
+ anchorColumnIndex < 0 ? columnIndex : anchorColumnIndex,
9499
+ columnIndex
9500
+ ),
9501
+ endColumnIndex: Math.max(
9502
+ anchorColumnIndex < 0 ? columnIndex : anchorColumnIndex,
9503
+ columnIndex
9504
+ )
9505
+ },
9506
+ selectedCellRanges: null
9507
+ };
9508
+ }
9509
+ if (params.ctrlKey) {
9510
+ const previous = params.previousCell;
9511
+ const previousColumnIndex = previous ? params.leafColumnKeys.indexOf(previous.columnKey) : -1;
9512
+ const ranges = params.current.selectedCellRanges ?? (params.current.selectedCellRange ? [params.current.selectedCellRange] : previous && previousColumnIndex >= 0 ? [
9513
+ {
9514
+ startRowIndex: previous.rowIndex,
9515
+ endRowIndex: previous.rowIndex,
9516
+ startColumnIndex: previousColumnIndex,
9517
+ endColumnIndex: previousColumnIndex
9518
+ }
9519
+ ] : []);
9520
+ const selected = ranges.some(
9521
+ (range) => isCellInHighlight(
9522
+ { selectedCellRange: range },
9523
+ params.rowIndex,
9524
+ columnIndex
9525
+ )
9526
+ );
9527
+ const nextRanges = selected ? ranges.flatMap(
9528
+ (range) => removeCellFromHighlightRange(range, params.rowIndex, columnIndex)
9529
+ ) : [
9530
+ ...ranges,
9531
+ {
9532
+ startRowIndex: params.rowIndex,
9533
+ endRowIndex: params.rowIndex,
9534
+ startColumnIndex: columnIndex,
9535
+ endColumnIndex: columnIndex
9536
+ }
9537
+ ];
9538
+ return {
9539
+ ...base,
9540
+ selectedCellAnchor: selected ? params.current.selectedCellAnchor ?? null : {
9541
+ rowIndex: params.rowIndex,
9542
+ columnKey: params.columnKey
9543
+ },
9544
+ selectedCellRange: null,
9545
+ selectedCellRanges: nextRanges
9546
+ };
9547
+ }
9548
+ return {
9549
+ ...params.current,
9550
+ selectedCellAnchor: {
9551
+ rowIndex: params.rowIndex,
9552
+ columnKey: params.columnKey
9553
+ },
9554
+ selectedCellRange: null,
9555
+ selectedCellRanges: null
9556
+ };
9557
+ }
9558
+ function removeCellFromHighlightRange(range, rowIndex, columnIndex) {
9559
+ return subtractCellHighlightRange(range, {
9560
+ startRowIndex: rowIndex,
9561
+ endRowIndex: rowIndex,
9562
+ startColumnIndex: columnIndex,
9563
+ endColumnIndex: columnIndex
9564
+ });
9565
+ }
9566
+ function subtractCellHighlightRange(range, cut) {
9567
+ const top = Math.max(range.startRowIndex, cut.startRowIndex);
9568
+ const bottom = Math.min(range.endRowIndex, cut.endRowIndex);
9569
+ const left = Math.max(range.startColumnIndex, cut.startColumnIndex);
9570
+ const right = Math.min(range.endColumnIndex, cut.endColumnIndex);
9571
+ if (top > bottom || left > right) {
9572
+ return [range];
9573
+ }
9574
+ return [
9575
+ ...range.startRowIndex < top ? [{ ...range, endRowIndex: top - 1 }] : [],
9576
+ ...bottom < range.endRowIndex ? [{ ...range, startRowIndex: bottom + 1 }] : [],
9577
+ ...range.startColumnIndex < left ? [
9578
+ {
9579
+ startRowIndex: top,
9580
+ endRowIndex: bottom,
9581
+ startColumnIndex: range.startColumnIndex,
9582
+ endColumnIndex: left - 1
9583
+ }
9584
+ ] : [],
9585
+ ...right < range.endColumnIndex ? [
9586
+ {
9587
+ startRowIndex: top,
9588
+ endRowIndex: bottom,
9589
+ startColumnIndex: right + 1,
9590
+ endColumnIndex: range.endColumnIndex
9591
+ }
9592
+ ] : []
9593
+ ];
9594
+ }
9595
+ function resolveRowHighlightForDrag(params) {
9596
+ const target = createHighlightRange(params.startRowIndex, params.endRowIndex);
9597
+ const ranges = params.current.selectedRowRanges ?? (params.current.selectedRowRange ? [params.current.selectedRowRange] : []);
9598
+ const nextRanges = params.remove ? ranges.flatMap(
9599
+ (range) => target.end < range.start || target.start > range.end ? [range] : [
9600
+ ...range.start < target.start ? [{ start: range.start, end: target.start - 1 }] : [],
9601
+ ...target.end < range.end ? [{ start: target.end + 1, end: range.end }] : []
9602
+ ]
9603
+ ) : [...ranges, target];
9604
+ nextRanges.sort((left, right) => left.start - right.start);
9605
+ const mergedRanges = nextRanges.reduce(
9606
+ (merged, range) => {
9607
+ const previous = merged[merged.length - 1];
9608
+ if (previous && range.start <= previous.end + 1) {
9609
+ previous.end = Math.max(previous.end, range.end);
9610
+ } else {
9611
+ merged.push({ ...range });
9612
+ }
9613
+ return merged;
9614
+ },
9615
+ []
9616
+ );
9617
+ return {
9618
+ ...params.current,
9619
+ selectedRowAnchorIndex: params.remove ? mergedRanges[mergedRanges.length - 1]?.end ?? null : params.startRowIndex,
9620
+ selectedRowRange: null,
9621
+ selectedRowRanges: mergedRanges,
9622
+ selectedColumnAnchorKey: null,
9623
+ selectedColumnRange: null,
9624
+ selectedColumnKeys: null
9625
+ };
9626
+ }
9627
+ function resolveCellHighlightForDrag(params) {
9628
+ const target = {
9629
+ startRowIndex: Math.min(params.startRowIndex, params.endRowIndex),
9630
+ endRowIndex: Math.max(params.startRowIndex, params.endRowIndex),
9631
+ startColumnIndex: Math.min(params.startColumnIndex, params.endColumnIndex),
9632
+ endColumnIndex: Math.max(params.startColumnIndex, params.endColumnIndex)
9633
+ };
9634
+ const ranges = params.current.selectedCellRanges ?? (params.current.selectedCellRange ? [params.current.selectedCellRange] : []);
9635
+ return {
9636
+ ...params.current,
9637
+ selectedRowAnchorIndex: params.preserveRowSelection ? params.current.selectedRowAnchorIndex : null,
9638
+ selectedRowRange: params.preserveRowSelection ? params.current.selectedRowRange : null,
9639
+ selectedRowRanges: params.preserveRowSelection ? params.current.selectedRowRanges ?? null : null,
9640
+ selectedColumnAnchorKey: null,
9641
+ selectedColumnRange: null,
9642
+ selectedColumnKeys: null,
9643
+ selectedCellAnchor: {
9644
+ rowIndex: params.startRowIndex,
9645
+ columnKey: params.columnKey
9646
+ },
9647
+ selectedCellRange: null,
9648
+ selectedCellRanges: params.remove ? ranges.flatMap((range) => subtractCellHighlightRange(range, target)) : [...ranges, target]
9649
+ };
9650
+ }
9651
+ function resolveNextRowHighlight(params) {
9652
+ return resolveNextRowHighlightByIndexRange({
9653
+ current: params.current,
9654
+ rangeStartIndex: params.rowIndex,
9655
+ rangeEndIndex: params.rowIndex,
9656
+ shiftKey: params.shiftKey
9657
+ });
9658
+ }
9659
+ function resolveNextRowHighlightByIndexRange(params) {
9660
+ const rangeStartIndex = Math.max(0, Math.floor(params.rangeStartIndex));
9661
+ const rangeEndIndex = Math.max(
9662
+ rangeStartIndex,
9663
+ Math.floor(params.rangeEndIndex)
9664
+ );
9665
+ const anchor = params.shiftKey && params.current.selectedRowAnchorIndex != null ? params.current.selectedRowAnchorIndex : rangeStartIndex;
9666
+ return {
9667
+ ...params.current,
9668
+ selectedRowAnchorIndex: anchor,
9669
+ selectedRowRange: createHighlightRange(anchor, rangeEndIndex),
9670
+ selectedRowRanges: null
9671
+ };
9672
+ }
9673
+ function resolveNextRowHighlightForContextMenu(params) {
9674
+ if (isRowInHighlight(params.current, params.rowIndex)) {
9675
+ return params.current;
9676
+ }
9677
+ return resolveNextRowHighlight({
9678
+ current: params.current,
9679
+ rowIndex: params.rowIndex,
9680
+ shiftKey: false
9681
+ });
9682
+ }
9683
+ function resolveNextColumnHighlightForContextMenu(params) {
9684
+ const currentRange = params.current.selectedColumnRange;
9685
+ const selectedKeys = params.current.selectedColumnKeys;
9686
+ if (selectedKeys?.length && params.leafColumnKeys.slice(params.rangeStartIndex, params.rangeEndIndex + 1).every((key) => selectedKeys.includes(key))) {
9687
+ return {
9688
+ ...params.current,
9689
+ selectedRowAnchorIndex: null,
9690
+ selectedRowRange: null
9691
+ };
9692
+ }
9693
+ if (currentRange && params.rangeStartIndex >= currentRange.start && params.rangeEndIndex <= currentRange.end) {
9694
+ return {
9695
+ ...params.current,
9696
+ selectedRowAnchorIndex: null,
9697
+ selectedRowRange: null
9698
+ };
9699
+ }
9700
+ return resolveNextColumnHighlightForHeaderClick({
9701
+ ...params,
9702
+ shiftKey: false
9703
+ });
9704
+ }
9705
+ function resolveColumnKeysForContextMenuAction(params) {
9706
+ const columnIndex = params.leafColumnKeys.indexOf(params.columnKey);
9707
+ const rangeStartIndex = params.rangeStartIndex ?? columnIndex;
9708
+ const rangeEndIndex = params.rangeEndIndex ?? columnIndex;
9709
+ const hasValidTargetRange = rangeStartIndex >= 0 && rangeEndIndex >= rangeStartIndex && rangeEndIndex < params.leafColumnKeys.length;
9710
+ const currentRange = params.current.selectedColumnRange;
9711
+ const selectedKeys = params.current.selectedColumnKeys;
9712
+ if (selectedKeys?.length && hasValidTargetRange && params.leafColumnKeys.slice(rangeStartIndex, rangeEndIndex + 1).every((key) => selectedKeys.includes(key))) {
9713
+ return params.leafColumnKeys.filter((key) => selectedKeys.includes(key));
9714
+ }
9715
+ if (currentRange && hasValidTargetRange && rangeStartIndex >= currentRange.start && rangeEndIndex <= currentRange.end) {
9716
+ return params.leafColumnKeys.slice(
9717
+ currentRange.start,
9718
+ currentRange.end + 1
9719
+ );
9720
+ }
9721
+ if (hasValidTargetRange) {
9722
+ return params.leafColumnKeys.slice(rangeStartIndex, rangeEndIndex + 1);
9723
+ }
9724
+ return [];
9725
+ }
9726
+ function resolveNextColumnHighlight(params) {
9727
+ const columnIndex = params.leafColumnKeys.indexOf(params.columnKey);
9728
+ if (columnIndex < 0) {
9729
+ return params.current;
9730
+ }
9731
+ return resolveNextColumnHighlightByIndexRange({
9732
+ current: params.current,
9733
+ columnKey: params.columnKey,
9734
+ leafColumnKeys: params.leafColumnKeys,
9735
+ rangeStartIndex: columnIndex,
9736
+ rangeEndIndex: columnIndex,
9737
+ shiftKey: params.shiftKey
9738
+ });
9739
+ }
9740
+ function resolveNextColumnHighlightForHeaderClick(params) {
9741
+ const nextCurrent = {
9742
+ ...params.current,
9743
+ selectedRowAnchorIndex: null,
9744
+ selectedRowRange: null,
9745
+ ...params.current.selectedRowRanges !== void 0 ? { selectedRowRanges: null } : {},
9746
+ selectedCellRange: null,
9747
+ selectedCellRanges: null,
9748
+ selectedCellAnchor: null
9749
+ };
9750
+ const hasValidRange = params.rangeStartIndex >= 0 && params.rangeEndIndex >= 0 && params.rangeStartIndex < params.leafColumnKeys.length && params.rangeEndIndex < params.leafColumnKeys.length;
9751
+ if (params.ctrlKey) {
9752
+ const leafIndex = params.leafColumnKeys.indexOf(params.columnKey);
9753
+ const targetKeys = hasValidRange ? params.leafColumnKeys.slice(
9754
+ params.rangeStartIndex,
9755
+ params.rangeEndIndex + 1
9756
+ ) : leafIndex >= 0 ? [params.columnKey] : [];
9757
+ if (!targetKeys.length) return nextCurrent;
9758
+ const selected = new Set(
9759
+ params.current.selectedColumnKeys ?? (params.current.selectedColumnRange ? params.leafColumnKeys.slice(
9760
+ params.current.selectedColumnRange.start,
9761
+ params.current.selectedColumnRange.end + 1
9762
+ ) : [])
9763
+ );
9764
+ if (targetKeys.every((key) => selected.has(key))) {
9765
+ targetKeys.forEach((key) => selected.delete(key));
9766
+ } else {
9767
+ targetKeys.forEach((key) => selected.add(key));
9768
+ }
9769
+ const selectedColumnKeys = params.leafColumnKeys.filter(
9770
+ (key) => selected.has(key)
9771
+ );
9772
+ return {
9773
+ ...nextCurrent,
9774
+ selectedColumnAnchorKey: selectedColumnKeys.length ? selected.has(params.columnKey) ? params.columnKey : selectedColumnKeys[selectedColumnKeys.length - 1] : null,
9775
+ selectedColumnRange: null,
9776
+ selectedColumnKeys
9777
+ };
9778
+ }
9779
+ if (!params.shiftKey) {
9780
+ const leafColumnIndex = params.leafColumnKeys.indexOf(params.columnKey);
9781
+ if (leafColumnIndex >= 0) {
9782
+ return resolveNextColumnHighlightByIndexRange({
9783
+ ...params,
9784
+ current: nextCurrent,
9785
+ rangeStartIndex: leafColumnIndex,
9786
+ rangeEndIndex: leafColumnIndex
9787
+ });
9788
+ }
9789
+ if (hasValidRange) {
9790
+ return resolveNextColumnHighlightByIndexRange({
9791
+ ...params,
9792
+ current: nextCurrent
9793
+ });
9794
+ }
9795
+ return {
9796
+ ...nextCurrent,
9797
+ selectedColumnAnchorKey: params.columnKey,
9798
+ selectedColumnRange: null,
9799
+ selectedColumnKeys: null
9800
+ };
9801
+ }
9802
+ if (hasValidRange) {
9803
+ return resolveNextColumnHighlightByIndexRange({
9804
+ ...params,
9805
+ current: nextCurrent
9806
+ });
9807
+ }
9808
+ return resolveNextColumnHighlight({
9809
+ current: nextCurrent,
9810
+ columnKey: params.columnKey,
9811
+ leafColumnKeys: params.leafColumnKeys,
9812
+ shiftKey: params.shiftKey
9813
+ });
9814
+ }
9815
+ function resolveNextColumnHighlightByIndexRange(params) {
9816
+ if (params.rangeStartIndex < 0 || params.rangeEndIndex < 0 || params.rangeStartIndex >= params.leafColumnKeys.length || params.rangeEndIndex >= params.leafColumnKeys.length) {
9817
+ return params.current;
9818
+ }
9819
+ const anchorIndex = resolveColumnAnchorIndex({
9820
+ anchorKey: params.current.selectedColumnAnchorKey,
9821
+ leafColumnKeys: params.leafColumnKeys
9822
+ });
9823
+ const nextAnchorIndex = params.shiftKey && anchorIndex != null ? anchorIndex : params.rangeStartIndex;
9824
+ return {
9825
+ ...params.current,
9826
+ selectedColumnAnchorKey: params.leafColumnKeys[nextAnchorIndex] ?? params.columnKey,
9827
+ selectedColumnRange: createHighlightRange(
9828
+ nextAnchorIndex,
9829
+ params.shiftKey ? params.rangeEndIndex : params.rangeEndIndex
9830
+ ),
9831
+ selectedColumnKeys: null
9832
+ };
9833
+ }
9834
+ function resolveColumnAnchorIndex(params) {
9835
+ if (!params.anchorKey) {
9836
+ return null;
9837
+ }
9838
+ const anchorIndex = params.leafColumnKeys.indexOf(params.anchorKey);
9839
+ return anchorIndex >= 0 ? anchorIndex : null;
9840
+ }
9841
+ function createHighlightRange(start, end) {
9842
+ return {
9843
+ start: Math.min(start, end),
9844
+ end: Math.max(start, end)
9845
+ };
9846
+ }
9847
+ function resolveHighlightMode(mode) {
9848
+ if (mode === "cell" || mode === "column" || mode === "cross") {
9849
+ return mode;
9850
+ }
9851
+ return "row";
9852
+ }
9853
+ function resolveRangeHighlightForHeaderSelection(params) {
9854
+ const nextRangeHighlight = {
9855
+ ...params.current,
9856
+ selectedRowAnchorIndex: null,
9857
+ selectedRowRange: null,
9858
+ ...params.current.selectedRowRanges !== void 0 ? { selectedRowRanges: null } : {}
9859
+ };
9860
+ if (!params.shiftKey && !params.ctrlKey) {
9861
+ nextRangeHighlight.selectedColumnAnchorKey = EMPTY_RANGE_HIGHLIGHT_STATE.selectedColumnAnchorKey;
9862
+ nextRangeHighlight.selectedColumnRange = EMPTY_RANGE_HIGHLIGHT_STATE.selectedColumnRange;
9863
+ if (params.current.selectedColumnKeys !== void 0) {
9864
+ nextRangeHighlight.selectedColumnKeys = null;
9865
+ }
9866
+ }
9867
+ return nextRangeHighlight;
9868
+ }
9869
+ function resolveRangeHighlightForBodyInteraction(params) {
9870
+ const mode = resolveHighlightMode(params.mode);
9871
+ const canHighlightColumn = params.columnKey !== params.selectionColumnKey && params.columnKey !== params.expandColumnKey;
9872
+ const rangeEndIndex = params.rowIndex + Math.max(Math.floor(params.rowSpan ?? 1), 1) - 1;
9873
+ if (mode === "cell") {
9874
+ return EMPTY_RANGE_HIGHLIGHT_STATE;
9875
+ }
9876
+ if (mode === "row") {
9877
+ return {
9878
+ ...resolveNextRowHighlightByIndexRange({
9879
+ current: params.current,
9880
+ rangeStartIndex: params.rowIndex,
9881
+ rangeEndIndex,
9882
+ shiftKey: params.shiftKey
9883
+ }),
9884
+ selectedColumnAnchorKey: null,
9885
+ selectedColumnRange: null,
9886
+ selectedColumnKeys: null,
9887
+ selectedCellRange: null,
9888
+ selectedCellRanges: null
9889
+ };
9890
+ }
9891
+ if (mode === "column") {
9892
+ if (!canHighlightColumn || !params.columnRange) {
9893
+ return {
9894
+ ...params.current,
9895
+ selectedRowAnchorIndex: null,
9896
+ selectedRowRange: null
9897
+ };
9898
+ }
9899
+ return {
9900
+ ...resolveNextColumnHighlightByIndexRange({
9901
+ current: params.current,
9902
+ columnKey: params.columnKey,
9903
+ leafColumnKeys: params.leafColumnKeys,
9904
+ rangeStartIndex: params.columnRange.start,
9905
+ rangeEndIndex: params.columnRange.end,
9906
+ shiftKey: params.shiftKey
9907
+ }),
9908
+ selectedRowAnchorIndex: null,
9909
+ selectedRowRange: null
9910
+ };
9911
+ }
9912
+ let next = resolveNextRowHighlightByIndexRange({
9913
+ current: params.current,
9914
+ rangeStartIndex: params.rowIndex,
9915
+ rangeEndIndex,
9916
+ shiftKey: params.shiftKey
9917
+ });
9918
+ if (canHighlightColumn && params.columnRange) {
9919
+ next = resolveNextColumnHighlightByIndexRange({
9920
+ current: next,
9921
+ columnKey: params.columnKey,
9922
+ leafColumnKeys: params.leafColumnKeys,
9923
+ rangeStartIndex: params.columnRange.start,
9924
+ rangeEndIndex: params.columnRange.end,
9925
+ shiftKey: false
9926
+ });
9927
+ }
9928
+ return next;
9929
+ }
9930
+ function isCellHighlightedByMode(params) {
9931
+ const mode = resolveHighlightMode(params.mode);
9932
+ if (mode === "cell") {
9933
+ return params.isCellSelected;
9934
+ }
9935
+ if (mode === "row") {
9936
+ return params.isRowRangeSelected;
9937
+ }
9938
+ if (mode === "column") {
9939
+ return params.isColumnRangeSelected;
9940
+ }
9941
+ return params.isRowRangeSelected || params.isColumnRangeSelected;
9942
+ }
9943
+
9944
+ // src/rendering/primitives/draw-summary.ts
9208
9945
  var EMPTY_RANGE_HIGHLIGHT2 = {
9209
9946
  selectedColumnRange: null
9210
9947
  };
@@ -9253,6 +9990,9 @@ function drawSummarySegment(params, columns, clipRect, defaultTitleColumnKey) {
9253
9990
  ctx.rect(minX, summaryTop, totalWidth, summaryHeight);
9254
9991
  ctx.clip();
9255
9992
  columns.forEach((column) => {
9993
+ if (clipRect && (column.drawX + column.width < clipRect.x - 1 || column.drawX > clipRect.x + clipRect.width + 1)) {
9994
+ return;
9995
+ }
9256
9996
  const rect = {
9257
9997
  x: column.drawX,
9258
9998
  y: summaryTop,
@@ -9290,9 +10030,10 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
9290
10030
  return;
9291
10031
  }
9292
10032
  const isHeaderColumnSelected = selectedHeaderKey != null && column.key === selectedHeaderKey;
9293
- const isColumnRangeSelected = isIndexInHighlightRange(
9294
- column.leafIndex,
9295
- (rangeHighlight ?? EMPTY_RANGE_HIGHLIGHT2).selectedColumnRange
10033
+ const isColumnRangeSelected = isColumnInHighlight(
10034
+ rangeHighlight ?? EMPTY_RANGE_HIGHLIGHT2,
10035
+ column.key,
10036
+ column.leafIndex
9296
10037
  );
9297
10038
  ctx.fillStyle = summarySelected || isHeaderColumnSelected || isColumnRangeSelected ? theme.selectionBackgroundColor : style?.backgroundColor ?? theme.headerBackgroundColor;
9298
10039
  ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
@@ -9505,9 +10246,6 @@ function intersectRects2(left, right) {
9505
10246
  height: maxY - y
9506
10247
  };
9507
10248
  }
9508
- function isIndexInHighlightRange(index, range) {
9509
- return Boolean(range && index >= range.start && index <= range.end);
9510
- }
9511
10249
 
9512
10250
  // src/rendering/cell-content/draw-nested-table-content.ts
9513
10251
  var DEFAULT_COLUMN_WIDTH2 = 140;
@@ -9577,7 +10315,8 @@ function drawBodyNestedTableContent(params) {
9577
10315
  align: column.align ?? "left",
9578
10316
  actionVisibilityState,
9579
10317
  allowActions: true,
9580
- hasFilter: column.allowFilter === true
10318
+ hasFilter: column.allowFilter === true,
10319
+ hasEdit: !!column.editable
9581
10320
  });
9582
10321
  const headerHighlighted = isNestedTableHeaderHighlighted(
9583
10322
  content,
@@ -9957,7 +10696,9 @@ function drawNestedTableHeaderActions(params) {
9957
10696
  if (!visibilityState.visible) return;
9958
10697
  const { actionTypes, startX, totalWidth } = getHeaderActionLayout({
9959
10698
  rect,
9960
- hasFilter: column.allowFilter === true
10699
+ hasFilter: column.allowFilter === true,
10700
+ hasEdit: !!column.editable,
10701
+ visibilityState
9961
10702
  });
9962
10703
  drawParams.ctx.save();
9963
10704
  drawParams.ctx.fillStyle = headerSelected ? drawParams.theme.selectionBackgroundColor : drawParams.theme.headerBackgroundColor;
@@ -9978,6 +10719,33 @@ function drawNestedTableHeaderActions(params) {
9978
10719
  width: size,
9979
10720
  height: size
9980
10721
  };
10722
+ if (actionType === "edit") {
10723
+ drawHeaderActionIcon(
10724
+ drawParams.ctx,
10725
+ actionRect,
10726
+ "edit",
10727
+ true,
10728
+ false,
10729
+ headerSelected,
10730
+ drawParams.theme.selectionBackgroundColor
10731
+ );
10732
+ drawParams.descriptors.push({
10733
+ kind: "body-content",
10734
+ rect: actionRect,
10735
+ columnKey: drawParams.column.key,
10736
+ rowIndex: drawParams.rowIndex,
10737
+ contentIndex: drawParams.contentIndex,
10738
+ contentKey: "nested-table",
10739
+ nestedColumnDataIndex: columnKey,
10740
+ nestedColumnIndex: columnIndex,
10741
+ fixed: drawParams.column.fixed,
10742
+ frozen: drawParams.frozen,
10743
+ debugNodeType: "nested-table-header-edit-icon",
10744
+ debugText: "\u5F53\u524D\u5217\u53EF\u7F16\u8F91"
10745
+ });
10746
+ actionX += size + gap;
10747
+ return;
10748
+ }
9981
10749
  const active = actionType === "sort" && sortOrder != null || actionType === "filter" && filtered || actionType === "fixed" && fixed != null;
9982
10750
  drawHeaderActionIcon(
9983
10751
  drawParams.ctx,
@@ -10021,7 +10789,7 @@ function resolveNestedTableHeaderActionVisibility(params) {
10021
10789
  sorted,
10022
10790
  filtered,
10023
10791
  fixed,
10024
- visible: hovered || sorted || filtered || fixed
10792
+ visible: hovered || sorted || filtered || fixed || !!column.editable
10025
10793
  };
10026
10794
  }
10027
10795
  function isNestedTableRowHighlighted(content, record, rowIndex, highlight, highlightMode) {
@@ -11597,7 +12365,7 @@ function drawBodyTagContent(params) {
11597
12365
  function measureTagContentWidth(ctx, content, theme) {
11598
12366
  applyTagTextStyle(ctx, content, theme);
11599
12367
  const intrinsicWidth = Math.max(
11600
- ctx.measureText(content.text).width + resolveContentTextIndent(content),
12368
+ measureCachedText(ctx, content.text).width + resolveContentTextIndent(content),
11601
12369
  0
11602
12370
  ) + (content.paddingInline ?? TAG_HORIZONTAL_PADDING) * 2;
11603
12371
  return resolveContentLayoutWidth(content, intrinsicWidth);
@@ -11737,8 +12505,8 @@ function drawBodyTextContent(params) {
11737
12505
  if (searchMatch && searchMatch.rowIndex === rowIndex && searchMatch.columnKey === column.key && (searchMatch.contentIndex == null || searchMatch.contentIndex === contentIndex) && searchMatch.keyword) {
11738
12506
  const start = Math.max(0, Math.min(searchMatch.start, content.text.length));
11739
12507
  const end = Math.max(start, Math.min(searchMatch.end, content.text.length));
11740
- const prefixWidth = ctx.measureText(content.text.slice(0, start)).width;
11741
- const matchWidth = ctx.measureText(content.text.slice(start, end)).width;
12508
+ const prefixWidth = measureCachedText(ctx, content.text.slice(0, start)).width;
12509
+ const matchWidth = measureCachedText(ctx, content.text.slice(start, end)).width;
11742
12510
  ctx.save();
11743
12511
  ctx.fillStyle = "#f59e0b";
11744
12512
  ctx.globalAlpha = 0.35;
@@ -11811,7 +12579,7 @@ function measureTextContentWidth(ctx, content, theme) {
11811
12579
  }
11812
12580
  applyTextContentStyle(ctx, content, theme.textColor, theme);
11813
12581
  const intrinsicWidth = Math.max(
11814
- ctx.measureText(content.text).width + resolveContentTextIndent(content),
12582
+ measureCachedText(ctx, content.text).width + resolveContentTextIndent(content),
11815
12583
  0
11816
12584
  );
11817
12585
  return resolveContentLayoutWidth(content, intrinsicWidth);
@@ -15110,6 +15878,7 @@ function createListTableAnimationRuntime() {
15110
15878
  lastExpandedRowKeys: /* @__PURE__ */ new Set(),
15111
15879
  expandAnimationFrameId: null,
15112
15880
  collapseRowAnimations: /* @__PURE__ */ new Map(),
15881
+ sortRowAnimations: /* @__PURE__ */ new Map(),
15113
15882
  collapseCellHeightAnimations: /* @__PURE__ */ new Map(),
15114
15883
  collapseAnimationFrameId: null,
15115
15884
  nestedTableHighlights: /* @__PURE__ */ new Map(),
@@ -16179,8 +16948,11 @@ function resolveCollapsedRowRange(params) {
16179
16948
 
16180
16949
  // src/engine/controllers/animation-controller.ts
16181
16950
  var ROW_EXPAND_ANIMATION_DURATION = 240;
16951
+ var ROW_SORT_ANIMATION_DURATION = 420;
16182
16952
  var ListTableAnimationController = class {
16183
16953
  constructor(options) {
16954
+ __publicField(this, "pendingSortRowPositions", null);
16955
+ __publicField(this, "sortRowsReady", false);
16184
16956
  __publicField(this, "runtime");
16185
16957
  __publicField(this, "getScrollbarVisibleOption");
16186
16958
  __publicField(this, "isScrollbarVisible");
@@ -16327,6 +17099,37 @@ var ListTableAnimationController = class {
16327
17099
  setPendingCollapseRowPositions(positions) {
16328
17100
  this.runtime.pendingCollapseRowPositions = positions;
16329
17101
  }
17102
+ /** 在排序前捕获可视行;异步查询完成之前不消费旧位置。 */
17103
+ setPendingSortRowPositions(positions, ready = false) {
17104
+ this.pendingSortRowPositions = positions;
17105
+ this.sortRowsReady = ready;
17106
+ }
17107
+ markSortRowsReady() {
17108
+ if (this.pendingSortRowPositions) this.sortRowsReady = true;
17109
+ }
17110
+ hasPendingSortRows() {
17111
+ return this.pendingSortRowPositions != null;
17112
+ }
17113
+ reconcileSortAnimations(snapshot) {
17114
+ if (!this.sortRowsReady || !this.pendingSortRowPositions) return false;
17115
+ const previousPositions = this.pendingSortRowPositions;
17116
+ this.pendingSortRowPositions = null;
17117
+ this.sortRowsReady = false;
17118
+ const now2 = this.scheduler.now();
17119
+ this.runtime.sortRowAnimations.clear();
17120
+ forEachRenderedVisibleRow(snapshot, (row, nextIndex) => {
17121
+ if (row.kind !== "data") return;
17122
+ const previousIndex = previousPositions.get(String(row.rowKey));
17123
+ if (previousIndex == null || previousIndex === nextIndex) return;
17124
+ this.runtime.sortRowAnimations.set(String(row.rowKey), {
17125
+ from: (previousIndex - nextIndex) * snapshot.rowHeight,
17126
+ to: 0,
17127
+ startTime: now2,
17128
+ duration: ROW_SORT_ANIMATION_DURATION
17129
+ });
17130
+ });
17131
+ return true;
17132
+ }
16330
17133
  reconcileCollapseAnimations(snapshot) {
16331
17134
  const previousPositions = this.runtime.pendingCollapseRowPositions;
16332
17135
  if (!previousPositions) {
@@ -16395,11 +17198,12 @@ var ListTableAnimationController = class {
16395
17198
  return getRowAnimationValue(animation, this.scheduler.now());
16396
17199
  }
16397
17200
  getCollapseRowOffset(rowKey) {
16398
- const animation = this.runtime.collapseRowAnimations.get(String(rowKey));
16399
- if (!animation) {
16400
- return void 0;
16401
- }
16402
- return getRowAnimationValue(animation, this.scheduler.now());
17201
+ const key = String(rowKey);
17202
+ const now2 = this.scheduler.now();
17203
+ const collapse = this.runtime.collapseRowAnimations.get(key);
17204
+ const sort = this.runtime.sortRowAnimations.get(key);
17205
+ if (!collapse && !sort) return void 0;
17206
+ return (collapse ? getRowAnimationValue(collapse, now2) : 0) + (sort ? getRowAnimationValue(sort, now2) : 0);
16403
17207
  }
16404
17208
  getCollapseCellHeight(params) {
16405
17209
  const animation = this.runtime.collapseCellHeightAnimations.get(
@@ -16428,13 +17232,16 @@ var ListTableAnimationController = class {
16428
17232
  columnKey: this.runtime.controlAnimationColumnKey,
16429
17233
  displayRows: snapshot.displayRows,
16430
17234
  nextWindowKey: buildControlAnimationWindowKey(snapshot),
16431
- nextColumnKey: buildControlAnimationColumnKey(snapshot.leafColumns)
17235
+ nextColumnKey: buildControlAnimationColumnKey(
17236
+ collectVisibleControlColumns(snapshot)
17237
+ )
16432
17238
  });
16433
17239
  }
16434
17240
  reconcileControlAnimations(snapshot, resolveCellContents = resolveBodyCellContents) {
16435
17241
  const now2 = this.scheduler.now();
16436
17242
  this.pruneFinishedControlAnimations(now2);
16437
17243
  const nextValues = /* @__PURE__ */ new Map();
17244
+ const visibleColumns = collectVisibleControlColumns(snapshot);
16438
17245
  forEachVisibleSnapshotRow(
16439
17246
  {
16440
17247
  frozenRows: snapshot.frozenRows,
@@ -16444,7 +17251,7 @@ var ListTableAnimationController = class {
16444
17251
  },
16445
17252
  (record, rowIndex) => {
16446
17253
  const rowKey = this.getRowKey(record, rowIndex);
16447
- collectVisibleControlColumns(snapshot).forEach((column) => {
17254
+ visibleColumns.forEach((column) => {
16448
17255
  const contents = resolveCellContents({
16449
17256
  record,
16450
17257
  rowIndex,
@@ -16487,9 +17294,7 @@ var ListTableAnimationController = class {
16487
17294
  this.runtime.lastControlValues = nextValues;
16488
17295
  this.runtime.controlAnimationRowsRef = snapshot.displayRows;
16489
17296
  this.runtime.controlAnimationWindowKey = buildControlAnimationWindowKey(snapshot);
16490
- this.runtime.controlAnimationColumnKey = buildControlAnimationColumnKey(
16491
- snapshot.leafColumns
16492
- );
17297
+ this.runtime.controlAnimationColumnKey = buildControlAnimationColumnKey(visibleColumns);
16493
17298
  Array.from(this.runtime.controlAnimations.keys()).forEach((key) => {
16494
17299
  if (!nextValues.has(key)) {
16495
17300
  this.runtime.controlAnimations.delete(key);
@@ -16867,7 +17672,7 @@ var ListTableAnimationController = class {
16867
17672
  );
16868
17673
  }
16869
17674
  ensureCollapseAnimationFrame() {
16870
- if (this.runtime.collapseRowAnimations.size === 0 && this.runtime.collapseCellHeightAnimations.size === 0 || this.runtime.collapseAnimationFrameId != null) {
17675
+ if (this.runtime.collapseRowAnimations.size === 0 && this.runtime.sortRowAnimations.size === 0 && this.runtime.collapseCellHeightAnimations.size === 0 || this.runtime.collapseAnimationFrameId != null) {
16871
17676
  return;
16872
17677
  }
16873
17678
  this.runtime.collapseAnimationFrameId = this.scheduler.requestAnimationFrame(() => {
@@ -16891,8 +17696,11 @@ var ListTableAnimationController = class {
16891
17696
  this.runtime.collapseAnimationFrameId = null;
16892
17697
  }
16893
17698
  this.runtime.collapseRowAnimations.clear();
17699
+ this.runtime.sortRowAnimations.clear();
16894
17700
  this.runtime.collapseCellHeightAnimations.clear();
16895
17701
  this.runtime.pendingCollapseRowPositions = null;
17702
+ this.pendingSortRowPositions = null;
17703
+ this.sortRowsReady = false;
16896
17704
  }
16897
17705
  destroy() {
16898
17706
  this.stopScrollbarOpacityAnimation();
@@ -16999,6 +17807,7 @@ var ListTableAnimationController = class {
16999
17807
  }
17000
17808
  pruneFinishedCollapseAnimations(now2) {
17001
17809
  pruneFinishedAnimations(this.runtime.collapseRowAnimations, now2);
17810
+ pruneFinishedAnimations(this.runtime.sortRowAnimations, now2);
17002
17811
  pruneFinishedAnimations(this.runtime.collapseCellHeightAnimations, now2);
17003
17812
  }
17004
17813
  };
@@ -17009,7 +17818,11 @@ function collectVisibleControlColumns(snapshot) {
17009
17818
  }
17010
17819
  const columns = [
17011
17820
  ...segments.leftSegment,
17012
- ...segments.centerSegment,
17821
+ ...segments.centerSegment.filter((column) => {
17822
+ const metrics = snapshot.columnMetrics;
17823
+ if (!metrics) return true;
17824
+ return metrics.availableCenterWidth > 0 && column.drawX + column.width >= metrics.fixedWidthLeft - 1 && column.drawX <= metrics.fixedWidthLeft + metrics.availableCenterWidth + 1;
17825
+ }),
17013
17826
  ...segments.rightSegment
17014
17827
  ];
17015
17828
  const seen = /* @__PURE__ */ new Set();
@@ -17828,8 +18641,11 @@ function createListTableSelectionCopyText(params) {
17828
18641
  (column2) => column2.key !== ROW_SELECTION_COLUMN_KEY && column2.key !== ROW_SELECTOR_COLUMN_KEY && column2.key !== EXPAND_COLUMN_KEY
17829
18642
  );
17830
18643
  const columnRange = params.rangeHighlight.selectedColumnRange;
18644
+ const selectedColumnKeys = params.rangeHighlight.selectedColumnKeys;
17831
18645
  const rowRange = params.rangeHighlight.selectedRowRange;
18646
+ const rowRanges = params.rangeHighlight.selectedRowRanges;
17832
18647
  const cellRange = params.rangeHighlight.selectedCellRange;
18648
+ const cellRanges = params.rangeHighlight.selectedCellRanges;
17833
18649
  if (cellRange) {
17834
18650
  const selectedColumns2 = params.columns.filter(
17835
18651
  (column2, index) => index >= cellRange.startColumnIndex && index <= cellRange.endColumnIndex && column2.key !== ROW_SELECTION_COLUMN_KEY && column2.key !== ROW_SELECTOR_COLUMN_KEY && column2.key !== EXPAND_COLUMN_KEY
@@ -17850,22 +18666,57 @@ function createListTableSelectionCopyText(params) {
17850
18666
  return `${headerText}
17851
18667
  ${bodyText}`;
17852
18668
  }
17853
- const mode = params.highlightMode ?? (rowRange && columnRange ? "cross" : rowRange ? "row" : "column");
17854
- const selectedColumns = columnRange ? params.columns.filter(
18669
+ if (cellRanges != null) {
18670
+ const lines = [];
18671
+ const fullRowRanges = rowRanges ?? (rowRange ? [rowRange] : []);
18672
+ const selectedRowSpans = [
18673
+ ...cellRanges.map((range) => ({
18674
+ start: range.startRowIndex,
18675
+ end: range.endRowIndex
18676
+ })),
18677
+ ...fullRowRanges
18678
+ ].sort((left, right) => left.start - right.start);
18679
+ let lastRowIndex = -1;
18680
+ for (const range of selectedRowSpans) {
18681
+ for (let rowIndex2 = Math.max(range.start, lastRowIndex + 1, 0); rowIndex2 <= Math.min(range.end, params.rows.length - 1); rowIndex2++) {
18682
+ const fullRowSelected = fullRowRanges.some(
18683
+ (rowRange2) => rowIndex2 >= rowRange2.start && rowIndex2 <= rowRange2.end
18684
+ );
18685
+ const selectedColumns2 = params.columns.filter(
18686
+ (column2, columnIndex) => column2.key !== ROW_SELECTION_COLUMN_KEY && column2.key !== ROW_SELECTOR_COLUMN_KEY && column2.key !== EXPAND_COLUMN_KEY && (fullRowSelected || cellRanges.some(
18687
+ (cellRange2) => rowIndex2 >= cellRange2.startRowIndex && rowIndex2 <= cellRange2.endRowIndex && columnIndex >= cellRange2.startColumnIndex && columnIndex <= cellRange2.endColumnIndex
18688
+ ))
18689
+ );
18690
+ if (selectedColumns2.length) {
18691
+ lines.push(
18692
+ selectedColumns2.map(
18693
+ (column2) => getCellClipboardText(params.rows[rowIndex2], rowIndex2, column2)
18694
+ ).join(" ")
18695
+ );
18696
+ }
18697
+ lastRowIndex = rowIndex2;
18698
+ }
18699
+ }
18700
+ return lines.length ? lines.join("\n") : null;
18701
+ }
18702
+ const mode = params.highlightMode ?? (rowRange && (columnRange || selectedColumnKeys?.length) ? "cross" : rowRange ? "row" : "column");
18703
+ const selectedColumns = selectedColumnKeys != null ? columns.filter((column2) => selectedColumnKeys.includes(column2.key)) : columnRange ? params.columns.filter(
17855
18704
  (column2, index) => index >= columnRange.start && index <= columnRange.end
17856
18705
  ).filter(
17857
18706
  (column2) => column2.key !== ROW_SELECTION_COLUMN_KEY && column2.key !== ROW_SELECTOR_COLUMN_KEY && column2.key !== EXPAND_COLUMN_KEY
17858
18707
  ) : columns;
17859
18708
  const startRow = rowRange ? Math.max(rowRange.start, 0) : 0;
17860
18709
  const endRow = rowRange ? Math.min(rowRange.end, params.rows.length - 1) : params.rows.length - 1;
17861
- if (rowRange && params.selection.columnKey === ROW_SELECTOR_COLUMN_KEY) {
17862
- return params.rows.slice(startRow, endRow + 1).map(
17863
- (record2, offset) => columns.map(
17864
- (column2) => getCellClipboardText(record2, startRow + offset, column2)
17865
- ).join(" ")
18710
+ if ((rowRange || rowRanges?.length) && params.selection.columnKey === ROW_SELECTOR_COLUMN_KEY) {
18711
+ const selectedRows = rowRanges != null ? rowRanges.flatMap((range) => {
18712
+ const start = Math.max(range.start, 0);
18713
+ return params.rows.slice(start, range.end + 1).map((record2, offset) => ({ record: record2, rowIndex: start + offset }));
18714
+ }) : params.rows.slice(startRow, endRow + 1).map((record2, offset) => ({ record: record2, rowIndex: startRow + offset }));
18715
+ return selectedRows.map(
18716
+ ({ record: record2, rowIndex: rowIndex2 }) => columns.map((column2) => getCellClipboardText(record2, rowIndex2, column2)).join(" ")
17866
18717
  ).join("\n");
17867
18718
  }
17868
- if (mode === "column" && columnRange && params.selection.rowIndex == null) {
18719
+ if ((mode === "column" || selectedColumnKeys != null) && (columnRange || selectedColumnKeys?.length) && params.selection.rowIndex == null) {
17869
18720
  return params.rows.map(
17870
18721
  (record2, rowIndex2) => selectedColumns.map((column2) => getCellClipboardText(record2, rowIndex2, column2)).join(" ")
17871
18722
  ).join("\n");
@@ -17965,42 +18816,99 @@ async function copyRowJsonContent(params) {
17965
18816
  }
17966
18817
  }
17967
18818
  async function exportAllRowsJsonContent(params) {
18819
+ const columns = resolveListTableExportColumns(
18820
+ params.columns,
18821
+ params.settings
18822
+ );
18823
+ const rows = await resolveListTableExportRows(
18824
+ params.rows,
18825
+ columns,
18826
+ params.settings
18827
+ );
18828
+ const data = mapRowsToExportRecords({
18829
+ rows,
18830
+ columns: buildExportColumns(columns)
18831
+ });
18832
+ const footerRows = await buildListTableExportFooterRows(
18833
+ rows,
18834
+ columns,
18835
+ params.settings
18836
+ );
18837
+ if (footerRows.length) {
18838
+ data.push(
18839
+ Object.fromEntries(
18840
+ columns.map((column, index) => [column.title, footerRows[0][index]])
18841
+ )
18842
+ );
18843
+ }
17968
18844
  await downloadJsonFile({
17969
18845
  fileName: params.fileName?.trim() || buildTableExportFileName("json"),
17970
- data: mapRowsToExportRecords({
17971
- rows: params.rows,
17972
- columns: buildExportColumns(params.columns)
17973
- })
18846
+ data
17974
18847
  });
17975
18848
  }
17976
18849
  async function exportAllRowsCsvContent(params) {
18850
+ const columns = resolveListTableExportColumns(
18851
+ params.columns,
18852
+ params.settings
18853
+ );
18854
+ const rows = await resolveListTableExportRows(
18855
+ params.rows,
18856
+ columns,
18857
+ params.settings
18858
+ );
17977
18859
  await exportTableToCsv({
17978
18860
  fileName: params.fileName?.trim() || buildTableExportFileName("csv"),
17979
- rows: params.rows,
17980
- columns: buildExportColumns(params.columns)
18861
+ rows,
18862
+ columns: buildExportColumns(columns),
18863
+ footerRows: await buildListTableExportFooterRows(
18864
+ rows,
18865
+ columns,
18866
+ params.settings
18867
+ )
17981
18868
  });
17982
18869
  }
17983
18870
  async function exportAllRowsTxtContent(params) {
18871
+ const columns = resolveListTableExportColumns(
18872
+ params.columns,
18873
+ params.settings
18874
+ );
18875
+ const rows = await resolveListTableExportRows(
18876
+ params.rows,
18877
+ columns,
18878
+ params.settings
18879
+ );
17984
18880
  await exportTableToTxt({
17985
18881
  fileName: params.fileName?.trim() || buildTableExportFileName("txt"),
17986
- rows: params.rows,
17987
- columns: buildExportColumns(params.columns)
18882
+ rows,
18883
+ columns: buildExportColumns(columns),
18884
+ footerRows: await buildListTableExportFooterRows(
18885
+ rows,
18886
+ columns,
18887
+ params.settings
18888
+ )
17988
18889
  });
17989
18890
  }
17990
18891
  async function exportAllRowsXlsxContent(params) {
17991
- const columns = params.columns.filter(isExportableColumn);
17992
- const footerRows = [];
17993
- if (params.includeSummary) {
17994
- const values = await computeSummaryValuesAsync({
17995
- rows: params.rows,
17996
- columns,
17997
- signal: params.signal
17998
- });
17999
- footerRows.push(columns.map((column) => values.get(column.key) ?? ""));
18000
- }
18892
+ const columns = resolveListTableExportColumns(
18893
+ params.columns,
18894
+ params.settings
18895
+ );
18896
+ const rows = await resolveListTableExportRows(
18897
+ params.rows,
18898
+ columns,
18899
+ params.settings,
18900
+ params.signal
18901
+ );
18902
+ const footerRows = await buildListTableExportFooterRows(
18903
+ rows,
18904
+ columns,
18905
+ params.settings,
18906
+ params.includeSummary,
18907
+ params.signal
18908
+ );
18001
18909
  await exportTableToXlsx({
18002
18910
  fileName: params.fileName?.trim() || buildTableExportFileName("xlsx"),
18003
- rows: params.rows,
18911
+ rows,
18004
18912
  footerRows,
18005
18913
  worker: params.worker,
18006
18914
  signal: params.signal,
@@ -18016,6 +18924,95 @@ async function exportAllRowsXlsxContent(params) {
18016
18924
  sheetName: "TableData"
18017
18925
  });
18018
18926
  }
18927
+ function getListTableExportCandidateColumns(columns) {
18928
+ const hiddenByKey = /* @__PURE__ */ new Map();
18929
+ const exportableByKey = /* @__PURE__ */ new Map();
18930
+ const reveal = (items, parentHidden = false) => items.map((column) => {
18931
+ const hidden = parentHidden || column.hidden === true;
18932
+ const key = resolveColumnKey(column);
18933
+ hiddenByKey.set(key, hidden);
18934
+ exportableByKey.set(key, column.exportable);
18935
+ return {
18936
+ ...column,
18937
+ hidden: false,
18938
+ ...column.children?.length ? { children: reveal(column.children, hidden) } : null
18939
+ };
18940
+ });
18941
+ return flattenLeafColumns(normalizeColumns(reveal(columns))).map(
18942
+ (column) => ({
18943
+ ...column,
18944
+ hidden: hiddenByKey.get(column.key) ?? false,
18945
+ exportable: exportableByKey.get(column.key)
18946
+ })
18947
+ );
18948
+ }
18949
+ function getListTableExportColumnChoices(columns, sortState = []) {
18950
+ return columns.filter(isExportableColumn).map((column) => ({
18951
+ key: column.key,
18952
+ title: column.title ?? column.key,
18953
+ selected: column.hidden !== true,
18954
+ sortOrder: sortState.find((item) => item.key === column.key)?.order ?? "default",
18955
+ sortIndex: sortState.findIndex((item) => item.key === column.key),
18956
+ sortPriority: sortState.find((item) => item.key === column.key)?.priority,
18957
+ summary: {
18958
+ type: column.summaryTitle != null ? "title" : column.summary === true ? "sum" : column.summary && typeof column.summary === "object" ? column.summary.type ?? "sum" : "none",
18959
+ showTypePrefix: column.summary === true || typeof column.summary === "object" && column.summary?.showTypePrefix !== false,
18960
+ precision: typeof column.summary === "object" && column.summary ? column.summary.precision : void 0,
18961
+ roundingMode: typeof column.summary === "object" && column.summary ? column.summary.roundingMode ?? "round" : "round",
18962
+ preserveTrailingZeros: typeof column.summary === "object" && column.summary ? column.summary.preserveTrailingZeros === true : false
18963
+ },
18964
+ ...column.summaryTitle != null ? { summaryTitle: column.summaryTitle } : null
18965
+ }));
18966
+ }
18967
+ function resolveListTableExportColumns(columns, settings) {
18968
+ const exportable = columns.filter(isExportableColumn);
18969
+ if (!settings) return exportable.filter((column) => !column.hidden);
18970
+ const byKey = new Map(exportable.map((column) => [column.key, column]));
18971
+ const selected = [...new Set(settings.columnKeys)].flatMap((key) => {
18972
+ const column = byKey.get(key);
18973
+ if (!column) return [];
18974
+ const summary = settings.summaries[key];
18975
+ if (!summary || summary.type === "original") return [column];
18976
+ const result = { ...column };
18977
+ if (summary.type === "none") {
18978
+ result.summary = false;
18979
+ delete result.summaryTitle;
18980
+ } else if (summary.type === "title") {
18981
+ result.summary = false;
18982
+ } else {
18983
+ result.summary = {
18984
+ ...typeof column.summary === "object" ? column.summary : null,
18985
+ type: summary.type,
18986
+ showTypePrefix: summary.showTypePrefix,
18987
+ precision: summary.precision,
18988
+ roundingMode: summary.roundingMode,
18989
+ preserveTrailingZeros: summary.preserveTrailingZeros
18990
+ };
18991
+ delete result.summaryTitle;
18992
+ }
18993
+ return [result];
18994
+ });
18995
+ if (selected.length === 0) throw new Error("\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u5217\u5BFC\u51FA\u3002");
18996
+ return selected;
18997
+ }
18998
+ async function resolveListTableExportRows(rows, columns, settings, signal) {
18999
+ if (!settings?.sortState.length) return rows;
19000
+ return sortRowsAsync({
19001
+ rows,
19002
+ leafColumns: columns,
19003
+ sortState: settings.sortState,
19004
+ signal
19005
+ });
19006
+ }
19007
+ async function buildListTableExportFooterRows(rows, columns, settings, includeSummary = false, signal) {
19008
+ if (!(settings?.includeSummary ?? includeSummary)) return [];
19009
+ const values = await computeSummaryValuesAsync({ rows, columns, signal });
19010
+ return [
19011
+ columns.map(
19012
+ (column) => resolveSummaryCellDisplayValue(column, values.get(column.key))
19013
+ )
19014
+ ];
19015
+ }
18019
19016
  function renderResultToClipboardText(result) {
18020
19017
  if (result == null) {
18021
19018
  return "";
@@ -18280,11 +19277,14 @@ var ListTableContentActionController = class {
18280
19277
  const includeSummary = options?.includeSummary ?? this.options.getSummaryVisible?.() ?? false;
18281
19278
  options = { ...this.options.getOptions().exportOptions, ...options };
18282
19279
  this.startExportTask(
18283
- (fileName) => exportAllRowsXlsxContent({
19280
+ (fileName, settings) => exportAllRowsXlsxContent({
18284
19281
  rows: this.options.getOptions().dataSource,
18285
- columns: this.options.getLeafColumns(),
19282
+ columns: getListTableExportCandidateColumns(
19283
+ this.options.getOptions().columns
19284
+ ),
18286
19285
  ...options,
18287
19286
  includeSummary,
19287
+ ...settings ? { settings } : null,
18288
19288
  fileName: fileName ?? options?.fileName,
18289
19289
  onProgress: (progress) => {
18290
19290
  const fileLabel = progress.fileCount && progress.fileCount > 1 ? `\uFF08\u7B2C ${progress.fileIndex}/${progress.fileCount} \u4EFD\uFF09` : "";
@@ -18297,10 +19297,17 @@ var ListTableContentActionController = class {
18297
19297
  "\u6B63\u5728\u5BFC\u51FA XLSX\u2026",
18298
19298
  options?.onError,
18299
19299
  options?.fileName?.trim() ? `${options.fileName.trim().replace(/\.xlsx$/i, "")}.xlsx` : buildTableExportFileName("xlsx"),
18300
- options?.promptFileName
19300
+ options?.promptFileName,
19301
+ {
19302
+ columns: getListTableExportColumnChoices(
19303
+ getListTableExportCandidateColumns(this.options.getOptions().columns),
19304
+ this.options.getSortState?.()
19305
+ ),
19306
+ includeSummary
19307
+ }
18301
19308
  );
18302
19309
  }
18303
- startExportTask(task, text, onError, defaultFileName, promptFileName = this.options.getOptions().exportOptions?.promptFileName ?? true) {
19310
+ startExportTask(task, text, onError, defaultFileName, promptFileName = this.options.getOptions().exportOptions?.promptFileName ?? true, dialog) {
18304
19311
  if (this.exportTaskRunning || this.exportNamePending) {
18305
19312
  return;
18306
19313
  }
@@ -18315,14 +19322,15 @@ var ListTableContentActionController = class {
18315
19322
  };
18316
19323
  const request = {
18317
19324
  fileName: defaultFileName,
18318
- onConfirm: (value) => {
19325
+ ...dialog,
19326
+ onConfirm: (value, settings) => {
18319
19327
  if (settled || !value.trim()) return;
18320
19328
  close();
18321
19329
  const extension = defaultFileName.match(
18322
19330
  /\.(xlsx|csv|txt|json)$/i
18323
19331
  )?.[0];
18324
19332
  const name = extension && !value.trim().toLowerCase().endsWith(extension.toLowerCase()) ? `${value.trim()}${extension}` : value.trim();
18325
- this.startExportTask(() => task(name), text, onError);
19333
+ this.startExportTask(() => task(name, settings), text, onError);
18326
19334
  },
18327
19335
  onCancel: () => {
18328
19336
  if (!settled) close();
@@ -19705,257 +20713,6 @@ function setColumnConditionalFormats(columns, key, rules, cache) {
19705
20713
  }
19706
20714
  return false;
19707
20715
  }
19708
-
19709
- // src/services/range-highlight-service.ts
19710
- var EMPTY_RANGE_HIGHLIGHT_STATE = {
19711
- selectedRowAnchorIndex: null,
19712
- selectedRowRange: null,
19713
- selectedColumnAnchorKey: null,
19714
- selectedColumnRange: null
19715
- };
19716
- function isIndexInHighlightRange2(index, range) {
19717
- return Boolean(range && index >= range.start && index <= range.end);
19718
- }
19719
- function resolveNextRowHighlight(params) {
19720
- return resolveNextRowHighlightByIndexRange({
19721
- current: params.current,
19722
- rangeStartIndex: params.rowIndex,
19723
- rangeEndIndex: params.rowIndex,
19724
- shiftKey: params.shiftKey
19725
- });
19726
- }
19727
- function resolveNextRowHighlightByIndexRange(params) {
19728
- const rangeStartIndex = Math.max(0, Math.floor(params.rangeStartIndex));
19729
- const rangeEndIndex = Math.max(
19730
- rangeStartIndex,
19731
- Math.floor(params.rangeEndIndex)
19732
- );
19733
- const anchor = params.shiftKey && params.current.selectedRowAnchorIndex != null ? params.current.selectedRowAnchorIndex : rangeStartIndex;
19734
- return {
19735
- ...params.current,
19736
- selectedRowAnchorIndex: anchor,
19737
- selectedRowRange: createHighlightRange(anchor, rangeEndIndex)
19738
- };
19739
- }
19740
- function resolveNextRowHighlightForContextMenu(params) {
19741
- if (isIndexInHighlightRange2(params.rowIndex, params.current.selectedRowRange)) {
19742
- return params.current;
19743
- }
19744
- return resolveNextRowHighlight({
19745
- current: params.current,
19746
- rowIndex: params.rowIndex,
19747
- shiftKey: false
19748
- });
19749
- }
19750
- function resolveNextColumnHighlightForContextMenu(params) {
19751
- const currentRange = params.current.selectedColumnRange;
19752
- if (currentRange && params.rangeStartIndex >= currentRange.start && params.rangeEndIndex <= currentRange.end) {
19753
- return {
19754
- ...params.current,
19755
- selectedRowAnchorIndex: null,
19756
- selectedRowRange: null
19757
- };
19758
- }
19759
- return resolveNextColumnHighlightForHeaderClick({
19760
- ...params,
19761
- shiftKey: false
19762
- });
19763
- }
19764
- function resolveColumnKeysForContextMenuAction(params) {
19765
- const columnIndex = params.leafColumnKeys.indexOf(params.columnKey);
19766
- const rangeStartIndex = params.rangeStartIndex ?? columnIndex;
19767
- const rangeEndIndex = params.rangeEndIndex ?? columnIndex;
19768
- const hasValidTargetRange = rangeStartIndex >= 0 && rangeEndIndex >= rangeStartIndex && rangeEndIndex < params.leafColumnKeys.length;
19769
- const currentRange = params.current.selectedColumnRange;
19770
- if (currentRange && hasValidTargetRange && rangeStartIndex >= currentRange.start && rangeEndIndex <= currentRange.end) {
19771
- return params.leafColumnKeys.slice(
19772
- currentRange.start,
19773
- currentRange.end + 1
19774
- );
19775
- }
19776
- if (hasValidTargetRange) {
19777
- return params.leafColumnKeys.slice(rangeStartIndex, rangeEndIndex + 1);
19778
- }
19779
- return [];
19780
- }
19781
- function resolveNextColumnHighlight(params) {
19782
- const columnIndex = params.leafColumnKeys.indexOf(params.columnKey);
19783
- if (columnIndex < 0) {
19784
- return params.current;
19785
- }
19786
- return resolveNextColumnHighlightByIndexRange({
19787
- current: params.current,
19788
- columnKey: params.columnKey,
19789
- leafColumnKeys: params.leafColumnKeys,
19790
- rangeStartIndex: columnIndex,
19791
- rangeEndIndex: columnIndex,
19792
- shiftKey: params.shiftKey
19793
- });
19794
- }
19795
- function resolveNextColumnHighlightForHeaderClick(params) {
19796
- const nextCurrent = {
19797
- ...params.current,
19798
- selectedRowAnchorIndex: null,
19799
- selectedRowRange: null
19800
- };
19801
- const hasValidRange = params.rangeStartIndex >= 0 && params.rangeEndIndex >= 0 && params.rangeStartIndex < params.leafColumnKeys.length && params.rangeEndIndex < params.leafColumnKeys.length;
19802
- if (!params.shiftKey) {
19803
- const leafColumnIndex = params.leafColumnKeys.indexOf(params.columnKey);
19804
- if (leafColumnIndex >= 0) {
19805
- return resolveNextColumnHighlightByIndexRange({
19806
- ...params,
19807
- current: nextCurrent,
19808
- rangeStartIndex: leafColumnIndex,
19809
- rangeEndIndex: leafColumnIndex
19810
- });
19811
- }
19812
- if (hasValidRange) {
19813
- return resolveNextColumnHighlightByIndexRange({
19814
- ...params,
19815
- current: nextCurrent
19816
- });
19817
- }
19818
- return {
19819
- ...nextCurrent,
19820
- selectedColumnAnchorKey: params.columnKey,
19821
- selectedColumnRange: null
19822
- };
19823
- }
19824
- if (hasValidRange) {
19825
- return resolveNextColumnHighlightByIndexRange({
19826
- ...params,
19827
- current: nextCurrent
19828
- });
19829
- }
19830
- return resolveNextColumnHighlight({
19831
- current: nextCurrent,
19832
- columnKey: params.columnKey,
19833
- leafColumnKeys: params.leafColumnKeys,
19834
- shiftKey: params.shiftKey
19835
- });
19836
- }
19837
- function resolveNextColumnHighlightByIndexRange(params) {
19838
- if (params.rangeStartIndex < 0 || params.rangeEndIndex < 0 || params.rangeStartIndex >= params.leafColumnKeys.length || params.rangeEndIndex >= params.leafColumnKeys.length) {
19839
- return params.current;
19840
- }
19841
- const anchorIndex = resolveColumnAnchorIndex({
19842
- anchorKey: params.current.selectedColumnAnchorKey,
19843
- leafColumnKeys: params.leafColumnKeys
19844
- });
19845
- const nextAnchorIndex = params.shiftKey && anchorIndex != null ? anchorIndex : params.rangeStartIndex;
19846
- return {
19847
- ...params.current,
19848
- selectedColumnAnchorKey: params.leafColumnKeys[nextAnchorIndex] ?? params.columnKey,
19849
- selectedColumnRange: createHighlightRange(
19850
- nextAnchorIndex,
19851
- params.shiftKey ? params.rangeEndIndex : params.rangeEndIndex
19852
- )
19853
- };
19854
- }
19855
- function resolveColumnAnchorIndex(params) {
19856
- if (!params.anchorKey) {
19857
- return null;
19858
- }
19859
- const anchorIndex = params.leafColumnKeys.indexOf(params.anchorKey);
19860
- return anchorIndex >= 0 ? anchorIndex : null;
19861
- }
19862
- function createHighlightRange(start, end) {
19863
- return {
19864
- start: Math.min(start, end),
19865
- end: Math.max(start, end)
19866
- };
19867
- }
19868
- function resolveHighlightMode(mode) {
19869
- if (mode === "cell" || mode === "column" || mode === "cross") {
19870
- return mode;
19871
- }
19872
- return "row";
19873
- }
19874
- function resolveRangeHighlightForHeaderSelection(params) {
19875
- const nextRangeHighlight = {
19876
- ...params.current,
19877
- selectedRowAnchorIndex: null,
19878
- selectedRowRange: null
19879
- };
19880
- if (!params.shiftKey) {
19881
- nextRangeHighlight.selectedColumnAnchorKey = EMPTY_RANGE_HIGHLIGHT_STATE.selectedColumnAnchorKey;
19882
- nextRangeHighlight.selectedColumnRange = EMPTY_RANGE_HIGHLIGHT_STATE.selectedColumnRange;
19883
- }
19884
- return nextRangeHighlight;
19885
- }
19886
- function resolveRangeHighlightForBodyInteraction(params) {
19887
- const mode = resolveHighlightMode(params.mode);
19888
- const canHighlightColumn = params.columnKey !== params.selectionColumnKey && params.columnKey !== params.expandColumnKey;
19889
- const rangeEndIndex = params.rowIndex + Math.max(Math.floor(params.rowSpan ?? 1), 1) - 1;
19890
- if (mode === "cell") {
19891
- return EMPTY_RANGE_HIGHLIGHT_STATE;
19892
- }
19893
- if (mode === "row") {
19894
- return {
19895
- ...resolveNextRowHighlightByIndexRange({
19896
- current: params.current,
19897
- rangeStartIndex: params.rowIndex,
19898
- rangeEndIndex,
19899
- shiftKey: params.shiftKey
19900
- }),
19901
- selectedColumnAnchorKey: null,
19902
- selectedColumnRange: null
19903
- };
19904
- }
19905
- if (mode === "column") {
19906
- if (!canHighlightColumn || !params.columnRange) {
19907
- return {
19908
- ...params.current,
19909
- selectedRowAnchorIndex: null,
19910
- selectedRowRange: null
19911
- };
19912
- }
19913
- return {
19914
- ...resolveNextColumnHighlightByIndexRange({
19915
- current: params.current,
19916
- columnKey: params.columnKey,
19917
- leafColumnKeys: params.leafColumnKeys,
19918
- rangeStartIndex: params.columnRange.start,
19919
- rangeEndIndex: params.columnRange.end,
19920
- shiftKey: params.shiftKey
19921
- }),
19922
- selectedRowAnchorIndex: null,
19923
- selectedRowRange: null
19924
- };
19925
- }
19926
- let next = resolveNextRowHighlightByIndexRange({
19927
- current: params.current,
19928
- rangeStartIndex: params.rowIndex,
19929
- rangeEndIndex,
19930
- shiftKey: params.shiftKey
19931
- });
19932
- if (canHighlightColumn && params.columnRange) {
19933
- next = resolveNextColumnHighlightByIndexRange({
19934
- current: next,
19935
- columnKey: params.columnKey,
19936
- leafColumnKeys: params.leafColumnKeys,
19937
- rangeStartIndex: params.columnRange.start,
19938
- rangeEndIndex: params.columnRange.end,
19939
- shiftKey: false
19940
- });
19941
- }
19942
- return next;
19943
- }
19944
- function isCellHighlightedByMode(params) {
19945
- const mode = resolveHighlightMode(params.mode);
19946
- if (mode === "cell") {
19947
- return params.isCellSelected;
19948
- }
19949
- if (mode === "row") {
19950
- return params.isRowRangeSelected;
19951
- }
19952
- if (mode === "column") {
19953
- return params.isColumnRangeSelected;
19954
- }
19955
- return params.isRowRangeSelected || params.isColumnRangeSelected;
19956
- }
19957
-
19958
- // src/rendering/primitives/draw-body.ts
19959
20716
  var VALIDATION_ERROR_COLOR = "#ff4d4f";
19960
20717
  var VALIDATION_TEXT_COLOR = "#ffffff";
19961
20718
  var VALIDATION_MUTED_TEXT_COLOR = "rgba(255, 255, 255, 0.72)";
@@ -20039,7 +20796,8 @@ function drawSegmentRows(params, segment, columns, startRowIndex, endRowIndex, r
20039
20796
  columns,
20040
20797
  startRowIndex,
20041
20798
  endRowIndex,
20042
- rowIndexMap: params.rowIndexMap
20799
+ rowIndexMap: params.rowIndexMap,
20800
+ horizontalClip: clipRect
20043
20801
  });
20044
20802
  const animatedCellHeights = /* @__PURE__ */ new Map();
20045
20803
  let collapseAnimationOverflow = 0;
@@ -20075,7 +20833,7 @@ function drawSegmentRows(params, segment, columns, startRowIndex, endRowIndex, r
20075
20833
  renderClipRect.height
20076
20834
  );
20077
20835
  ctx.clip();
20078
- const orderedCells = [...visibleCells].sort(
20836
+ const orderedCells = animatedCellHeights.size === 0 ? visibleCells : [...visibleCells].sort(
20079
20837
  (left, right) => Number(animatedCellHeights.has(left)) - Number(animatedCellHeights.has(right))
20080
20838
  );
20081
20839
  orderedCells.forEach((cell) => {
@@ -20101,7 +20859,7 @@ function drawSegmentRows(params, segment, columns, startRowIndex, endRowIndex, r
20101
20859
  width: getMergedCellWidth(columns, cell.columnIndex, cell.colSpan),
20102
20860
  height: animatedCellHeights.get(cell) ?? baseHeight
20103
20861
  };
20104
- if (rect.y + rect.height <= params.bodyTop || rect.y >= params.bodyTop + params.bodyHeight) {
20862
+ if (rect.x + rect.width < clipRect.x - 1 || rect.x > clipRect.x + clipRect.width + 1 || rect.y + rect.height <= params.bodyTop || rect.y >= params.bodyTop + params.bodyHeight) {
20105
20863
  return;
20106
20864
  }
20107
20865
  const isHovered = params.hover.area === "body" && params.hover.rowIndex === cell.sourceRowIndex && params.hover.columnKey === cell.column.key;
@@ -20109,24 +20867,28 @@ function drawSegmentRows(params, segment, columns, startRowIndex, endRowIndex, r
20109
20867
  const hasCellTextSelection = params.selection.textSelection?.fragments.some(
20110
20868
  (fragment) => fragment.rowIndex === cell.sourceRowIndex && fragment.columnKey === cell.column.key
20111
20869
  ) === true;
20112
- const isRowRangeSelected = cell.row.kind === "data" && isRowSpanInHighlightRange(
20113
- cell.sourceRowIndex,
20114
- cell.rowSpan,
20870
+ const isRowRangeSelected = cell.row.kind === "data" && (params.rangeHighlight?.selectedRowRanges ?? ((params.rangeHighlight ?? EMPTY_RANGE_HIGHLIGHT3).selectedRowRange ? [
20115
20871
  (params.rangeHighlight ?? EMPTY_RANGE_HIGHLIGHT3).selectedRowRange
20872
+ ] : [])).some(
20873
+ (range) => isRowSpanInHighlightRange(cell.sourceRowIndex, cell.rowSpan, range)
20116
20874
  );
20117
- const isColumnRangeSelected = cell.row.kind === "data" && isIndexInHighlightRange3(
20118
- cell.column.leafIndex,
20119
- (params.rangeHighlight ?? EMPTY_RANGE_HIGHLIGHT3).selectedColumnRange
20875
+ const isColumnRangeSelected = cell.row.kind === "data" && isColumnInHighlight(
20876
+ params.rangeHighlight ?? EMPTY_RANGE_HIGHLIGHT3,
20877
+ cell.column.key,
20878
+ cell.column.leafIndex
20879
+ );
20880
+ const isSelectedCellRange = cell.row.kind === "data" && isCellInHighlight(
20881
+ params.rangeHighlight ?? EMPTY_RANGE_HIGHLIGHT3,
20882
+ cell.sourceRowIndex,
20883
+ cell.column.leafIndex
20120
20884
  );
20121
- const selectedCellRange = (params.rangeHighlight ?? EMPTY_RANGE_HIGHLIGHT3).selectedCellRange;
20122
- const isSelectedCellRange = cell.row.kind === "data" && selectedCellRange != null && cell.sourceRowIndex >= selectedCellRange.startRowIndex && cell.sourceRowIndex <= selectedCellRange.endRowIndex && cell.column.leafIndex >= selectedCellRange.startColumnIndex && cell.column.leafIndex <= selectedCellRange.endColumnIndex;
20123
20885
  const isHeaderColumnSelected = cell.row.kind === "data" && params.selectedHeaderKey != null && cell.column.key === params.selectedHeaderKey;
20124
- const isRangeHighlighted = isCellHighlightedByMode({
20886
+ const isRangeHighlighted = isSelectedCellRange || isCellHighlightedByMode({
20125
20887
  mode: params.highlightMode,
20126
20888
  isCellSelected: isSelected || isSelectedCellRange,
20127
20889
  isRowRangeSelected,
20128
20890
  isColumnRangeSelected
20129
- });
20891
+ }) || params.selection.rowIndex == null && (params.selectedHeaderKey != null || (params.rangeHighlight ?? EMPTY_RANGE_HIGHLIGHT3).selectedColumnKeys != null) && isColumnRangeSelected;
20130
20892
  const validationMessage = cell.row.kind === "data" ? params.getValidationMessage?.({
20131
20893
  record: cell.record,
20132
20894
  rowIndex: cell.sourceRowIndex,
@@ -20458,9 +21220,6 @@ function findVisibleDataRow(rows, startIndex, step) {
20458
21220
  }
20459
21221
  return null;
20460
21222
  }
20461
- function isIndexInHighlightRange3(index, range) {
20462
- return Boolean(range && index >= range.start && index <= range.end);
20463
- }
20464
21223
  function isRowSpanInHighlightRange(rowIndex, rowSpan, range) {
20465
21224
  if (!range) {
20466
21225
  return false;
@@ -20555,6 +21314,14 @@ function buildMergedBodyCells(rows, columns, mergeCell, rowIndexMap) {
20555
21314
  function buildPlainVisibleBodyCells(params) {
20556
21315
  const { rows, columns, startRowIndex, endRowIndex } = params;
20557
21316
  const visibleCells = [];
21317
+ const clip = params.horizontalClip;
21318
+ const visibleColumnIndexes = [];
21319
+ for (let index = 0; index < columns.length; index += 1) {
21320
+ const column = columns[index];
21321
+ if (column && (!clip || column.drawX + column.width >= clip.x - 1 && column.drawX <= clip.x + clip.width + 1)) {
21322
+ visibleColumnIndexes.push(index);
21323
+ }
21324
+ }
20558
21325
  for (let rowIndex = startRowIndex; rowIndex < endRowIndex; rowIndex += 1) {
20559
21326
  const row = rows[rowIndex];
20560
21327
  if (!row) {
@@ -20578,7 +21345,7 @@ function buildPlainVisibleBodyCells(params) {
20578
21345
  continue;
20579
21346
  }
20580
21347
  const sourceRowIndex = row.dataRowIndex;
20581
- for (let columnIndex = 0; columnIndex < columns.length; columnIndex += 1) {
21348
+ for (const columnIndex of visibleColumnIndexes) {
20582
21349
  const column = columns[columnIndex];
20583
21350
  if (!column) {
20584
21351
  continue;
@@ -21560,7 +22327,7 @@ function getMaxDepth(columns) {
21560
22327
  var DEFAULT_HORIZONTAL_LEFT = 0;
21561
22328
  var DEFAULT_HORIZONTAL_RIGHT = 0;
21562
22329
  var DEFAULT_HORIZONTAL_BOTTOM = 0;
21563
- var DEFAULT_VERTICAL_TOP = 6;
22330
+ var DEFAULT_VERTICAL_TOP = 0;
21564
22331
  var DEFAULT_VERTICAL_RIGHT = 0;
21565
22332
  var DEFAULT_VERTICAL_BOTTOM = 0;
21566
22333
  var MIN_SCROLLBAR_THUMB_SIZE = 36;
@@ -21570,6 +22337,7 @@ function computeScrollbarLayout(params) {
21570
22337
  const vertical = resolveCanvasScrollbarAxis(params.scrollbar, "vertical");
21571
22338
  const horizontalLeft = Math.max(
21572
22339
  params.scrollbar?.horizontalLeft ?? DEFAULT_HORIZONTAL_LEFT,
22340
+ params.rowSelectorWidth ?? 0,
21573
22341
  0
21574
22342
  );
21575
22343
  const horizontalRight = Math.max(
@@ -21599,43 +22367,69 @@ function computeScrollbarLayout(params) {
21599
22367
  const horizontalTrackY = params.height - horizontal.thickness - horizontalBottom;
21600
22368
  if (horizontal.visible && params.maxScrollLeft > 0 && horizontalTrackWidth > 0) {
21601
22369
  const thickness = horizontal.thickness;
21602
- const buttonSize = Math.min(thickness, horizontalTrackWidth / 3);
21603
- const trackX = horizontalLeft + buttonSize;
21604
- const trackWidth = Math.max(horizontalTrackWidth - buttonSize * 2, 0);
21605
- const thumbWidth = Math.min(
21606
- Math.max(
21607
- params.centerVisibleWidth / params.centerContentWidth * trackWidth,
21608
- MIN_SCROLLBAR_THUMB_SIZE
21609
- ),
21610
- trackWidth
21611
- );
21612
- const thumbOffset = params.maxScrollLeft === 0 ? 0 : params.scrollLeft / params.maxScrollLeft * (trackWidth - thumbWidth);
21613
- layout.horizontal = {
21614
- decreaseButton: {
21615
- x: horizontalLeft,
21616
- y: horizontalTrackY,
21617
- width: buttonSize,
21618
- height: thickness
21619
- },
21620
- increaseButton: {
21621
- x: horizontalLeft + horizontalTrackWidth - buttonSize,
22370
+ if (horizontal.mode === "button") {
22371
+ const halfWidth = horizontalTrackWidth / 2;
22372
+ const empty = {
22373
+ x: horizontalLeft + halfWidth,
21622
22374
  y: horizontalTrackY,
21623
- width: buttonSize,
21624
- height: thickness
21625
- },
21626
- track: {
21627
- x: trackX,
21628
- y: horizontalTrackY,
21629
- width: trackWidth,
21630
- height: thickness
21631
- },
21632
- thumb: {
21633
- x: trackX + thumbOffset,
21634
- y: horizontalTrackY,
21635
- width: thumbWidth,
21636
- height: thickness
21637
- }
21638
- };
22375
+ width: 0,
22376
+ height: 0
22377
+ };
22378
+ layout.horizontal = {
22379
+ decreaseButton: {
22380
+ x: horizontalLeft,
22381
+ y: horizontalTrackY,
22382
+ width: halfWidth,
22383
+ height: thickness
22384
+ },
22385
+ increaseButton: {
22386
+ x: horizontalLeft + halfWidth,
22387
+ y: horizontalTrackY,
22388
+ width: horizontalTrackWidth - halfWidth,
22389
+ height: thickness
22390
+ },
22391
+ track: empty,
22392
+ thumb: empty
22393
+ };
22394
+ } else {
22395
+ const buttonSize = Math.min(thickness, horizontalTrackWidth / 3);
22396
+ const trackX = horizontalLeft + buttonSize;
22397
+ const trackWidth = Math.max(horizontalTrackWidth - buttonSize * 2, 0);
22398
+ const thumbWidth = Math.min(
22399
+ Math.max(
22400
+ params.centerVisibleWidth / params.centerContentWidth * trackWidth,
22401
+ MIN_SCROLLBAR_THUMB_SIZE
22402
+ ),
22403
+ trackWidth
22404
+ );
22405
+ const thumbOffset = params.maxScrollLeft === 0 ? 0 : params.scrollLeft / params.maxScrollLeft * (trackWidth - thumbWidth);
22406
+ layout.horizontal = {
22407
+ decreaseButton: {
22408
+ x: horizontalLeft,
22409
+ y: horizontalTrackY,
22410
+ width: buttonSize,
22411
+ height: thickness
22412
+ },
22413
+ increaseButton: {
22414
+ x: horizontalLeft + horizontalTrackWidth - buttonSize,
22415
+ y: horizontalTrackY,
22416
+ width: buttonSize,
22417
+ height: thickness
22418
+ },
22419
+ track: {
22420
+ x: trackX,
22421
+ y: horizontalTrackY,
22422
+ width: trackWidth,
22423
+ height: thickness
22424
+ },
22425
+ thumb: {
22426
+ x: trackX + thumbOffset,
22427
+ y: horizontalTrackY,
22428
+ width: thumbWidth,
22429
+ height: thickness
22430
+ }
22431
+ };
22432
+ }
21639
22433
  }
21640
22434
  const verticalTrackHeight = Math.max(
21641
22435
  params.bodyHeight - verticalTop - verticalBottom,
@@ -21645,43 +22439,69 @@ function computeScrollbarLayout(params) {
21645
22439
  const verticalTrackY = params.bodyTop + verticalTop;
21646
22440
  if (vertical.visible && params.maxScrollTop > 0 && verticalTrackHeight > 0) {
21647
22441
  const thickness = vertical.thickness;
21648
- const buttonSize = Math.min(thickness, verticalTrackHeight / 3);
21649
- const trackY = verticalTrackY + buttonSize;
21650
- const trackHeight = Math.max(verticalTrackHeight - buttonSize * 2, 0);
21651
- const thumbHeight = Math.min(
21652
- Math.max(
21653
- params.bodyHeight / params.totalBodyHeight * trackHeight,
21654
- MIN_SCROLLBAR_THUMB_SIZE
21655
- ),
21656
- trackHeight
21657
- );
21658
- const thumbOffset = params.maxScrollTop === 0 ? 0 : params.scrollTop / params.maxScrollTop * (trackHeight - thumbHeight);
21659
- layout.vertical = {
21660
- decreaseButton: {
21661
- x: verticalTrackX,
21662
- y: verticalTrackY,
21663
- width: thickness,
21664
- height: buttonSize
21665
- },
21666
- increaseButton: {
21667
- x: verticalTrackX,
21668
- y: verticalTrackY + verticalTrackHeight - buttonSize,
21669
- width: thickness,
21670
- height: buttonSize
21671
- },
21672
- track: {
21673
- x: verticalTrackX,
21674
- y: trackY,
21675
- width: thickness,
21676
- height: trackHeight
21677
- },
21678
- thumb: {
22442
+ if (vertical.mode === "button") {
22443
+ const halfHeight = verticalTrackHeight / 2;
22444
+ const empty = {
21679
22445
  x: verticalTrackX,
21680
- y: trackY + thumbOffset,
21681
- width: thickness,
21682
- height: thumbHeight
21683
- }
21684
- };
22446
+ y: verticalTrackY + halfHeight,
22447
+ width: 0,
22448
+ height: 0
22449
+ };
22450
+ layout.vertical = {
22451
+ decreaseButton: {
22452
+ x: verticalTrackX,
22453
+ y: verticalTrackY,
22454
+ width: thickness,
22455
+ height: halfHeight
22456
+ },
22457
+ increaseButton: {
22458
+ x: verticalTrackX,
22459
+ y: verticalTrackY + halfHeight,
22460
+ width: thickness,
22461
+ height: verticalTrackHeight - halfHeight
22462
+ },
22463
+ track: empty,
22464
+ thumb: empty
22465
+ };
22466
+ } else {
22467
+ const buttonSize = Math.min(thickness, verticalTrackHeight / 3);
22468
+ const trackY = verticalTrackY + buttonSize;
22469
+ const trackHeight = Math.max(verticalTrackHeight - buttonSize * 2, 0);
22470
+ const thumbHeight = Math.min(
22471
+ Math.max(
22472
+ params.bodyHeight / params.totalBodyHeight * trackHeight,
22473
+ MIN_SCROLLBAR_THUMB_SIZE
22474
+ ),
22475
+ trackHeight
22476
+ );
22477
+ const thumbOffset = params.maxScrollTop === 0 ? 0 : params.scrollTop / params.maxScrollTop * (trackHeight - thumbHeight);
22478
+ layout.vertical = {
22479
+ decreaseButton: {
22480
+ x: verticalTrackX,
22481
+ y: verticalTrackY,
22482
+ width: thickness,
22483
+ height: buttonSize
22484
+ },
22485
+ increaseButton: {
22486
+ x: verticalTrackX,
22487
+ y: verticalTrackY + verticalTrackHeight - buttonSize,
22488
+ width: thickness,
22489
+ height: buttonSize
22490
+ },
22491
+ track: {
22492
+ x: verticalTrackX,
22493
+ y: trackY,
22494
+ width: thickness,
22495
+ height: trackHeight
22496
+ },
22497
+ thumb: {
22498
+ x: verticalTrackX,
22499
+ y: trackY + thumbOffset,
22500
+ width: thickness,
22501
+ height: thumbHeight
22502
+ }
22503
+ };
22504
+ }
21685
22505
  }
21686
22506
  return layout;
21687
22507
  }
@@ -21899,30 +22719,25 @@ function resolveColumnSegments(params) {
21899
22719
  // src/domain/columns/header-layout.ts
21900
22720
  function buildHeaderLayouts(nodes, leafColumns, rightStartX, headerRowHeight, fixedWidthLeft, fixedWidthRight, scrollLeft) {
21901
22721
  const rows = /* @__PURE__ */ new Map();
21902
- const leftCols = leafColumns.filter((c) => c.fixed === "left");
21903
- const centerCols = leafColumns.filter((c) => !c.fixed);
21904
- const rightCols = leafColumns.filter((c) => c.fixed === "right");
21905
- function segmentOffset(cols, targetKey) {
21906
- let offset = 0;
21907
- for (const c of cols) {
21908
- if (c.key === targetKey) return offset;
21909
- offset += c.width;
21910
- }
21911
- return offset;
21912
- }
21913
- const getLeafX = (leafIndex) => {
21914
- const leaf = leafColumns[leafIndex];
21915
- if (!leaf) {
21916
- return 0;
21917
- }
22722
+ let leftX = 0;
22723
+ let centerX = fixedWidthLeft - scrollLeft;
22724
+ let rightX = rightStartX;
22725
+ const leafPositions = leafColumns.map((leaf) => {
21918
22726
  if (leaf.fixed === "left") {
21919
- return segmentOffset(leftCols, leaf.key);
22727
+ const x2 = leftX;
22728
+ leftX += leaf.width;
22729
+ return x2;
21920
22730
  }
21921
22731
  if (leaf.fixed === "right") {
21922
- return rightStartX + segmentOffset(rightCols, leaf.key);
22732
+ const x2 = rightX;
22733
+ rightX += leaf.width;
22734
+ return x2;
21923
22735
  }
21924
- return fixedWidthLeft + segmentOffset(centerCols, leaf.key) - scrollLeft;
21925
- };
22736
+ const x = centerX;
22737
+ centerX += leaf.width;
22738
+ return x;
22739
+ });
22740
+ const getLeafX = (leafIndex) => leafPositions[leafIndex] ?? 0;
21926
22741
  const visit = (node) => {
21927
22742
  const rowItems = rows.get(node.depth) ?? [];
21928
22743
  buildHeaderCellSegments(node, leafColumns, {
@@ -23523,13 +24338,15 @@ var AUTO_ROW_HEIGHT_SAMPLE_COUNT = 200;
23523
24338
  function buildListTableRenderSnapshot(params) {
23524
24339
  if (params.cache?.snapshot && params.cache.snapshot.groupIndex === params.cache.groupIndex && isSameRenderCacheInputs(params.cache.inputs, params)) {
23525
24340
  const snapshotStartedAt2 = resolvePerformanceNow3();
23526
- const snapshot2 = updateListTableRenderSnapshotScroll({
24341
+ const cached = params.cache.snapshot;
24342
+ const snapshot2 = !cached.swapAnimation && cached.scroll.left === params.scroll.left && cached.scroll.top === params.scroll.top ? cached : updateListTableRenderSnapshotScroll({
23527
24343
  snapshot: params.cache.snapshot,
23528
24344
  width: params.width,
23529
24345
  height: params.height,
23530
24346
  scroll: params.scroll,
23531
24347
  options: params.options
23532
24348
  });
24349
+ params.cache.snapshot = snapshot2;
23533
24350
  params.options.debug?.onPerformance?.({
23534
24351
  phase: "snapshot",
23535
24352
  durationMs: resolvePerformanceNow3() - snapshotStartedAt2,
@@ -23892,6 +24709,7 @@ function buildListTableRenderSnapshot(params) {
23892
24709
  });
23893
24710
  const scrollbarLayout = computeScrollbarLayout({
23894
24711
  width: hostWidth,
24712
+ rowSelectorWidth: leafColumns.find((column) => column.key === ROW_SELECTOR_COLUMN_KEY)?.width ?? 0,
23895
24713
  height: hostHeight,
23896
24714
  bodyTop: bodyState.bodyLayout.scrollBodyTop,
23897
24715
  bodyHeight: bodyState.bodyLayout.scrollBodyHeight,
@@ -24104,12 +24922,13 @@ function updateListTableRenderSnapshotScroll(params) {
24104
24922
  scroll
24105
24923
  });
24106
24924
  const nextScroll = viewportResult.scroll;
24107
- const columnSegments = resolveColumnSegments({
24925
+ const reuseHorizontalLayout = nextScroll.left === snapshot.scroll.left && !snapshot.swapAnimation;
24926
+ const columnSegments = reuseHorizontalLayout ? snapshot.columnSegments : resolveColumnSegments({
24108
24927
  metrics: snapshot.columnMetrics,
24109
24928
  scrollLeft: nextScroll.left,
24110
24929
  swapAnimation: snapshot.swapAnimation
24111
24930
  });
24112
- const headerRows = buildHeaderLayouts(
24931
+ const headerRows = reuseHorizontalLayout ? snapshot.headerRows : buildHeaderLayouts(
24113
24932
  snapshot.headerTree,
24114
24933
  snapshot.leafColumns,
24115
24934
  snapshot.columnMetrics.rightStartX,
@@ -24118,7 +24937,8 @@ function updateListTableRenderSnapshotScroll(params) {
24118
24937
  snapshot.columnMetrics.fixedWidthRight,
24119
24938
  nextScroll.left
24120
24939
  );
24121
- offsetHeaderRows(headerRows, snapshot.groupingBarHeight);
24940
+ if (!reuseHorizontalLayout)
24941
+ offsetHeaderRows(headerRows, snapshot.groupingBarHeight);
24122
24942
  if (snapshot.swapAnimation) {
24123
24943
  applyColumnSegmentPositionsToHeaderRows({
24124
24944
  headerRows,
@@ -24128,6 +24948,9 @@ function updateListTableRenderSnapshotScroll(params) {
24128
24948
  }
24129
24949
  const scrollbarLayout = computeScrollbarLayout({
24130
24950
  width,
24951
+ rowSelectorWidth: snapshot.leafColumns.find(
24952
+ (column) => column.key === ROW_SELECTOR_COLUMN_KEY
24953
+ )?.width ?? 0,
24131
24954
  height,
24132
24955
  bodyTop: snapshot.bodyLayout.scrollBodyTop,
24133
24956
  bodyHeight: snapshot.bodyLayout.scrollBodyHeight,
@@ -24466,7 +25289,7 @@ function buildListTableDebugSnapshot(params) {
24466
25289
  hitTest: hitTest2.area === "empty" ? void 0 : hitTest2
24467
25290
  };
24468
25291
  }
24469
- function drawScrollbars(ctx, layout, descriptors, borderColor, opacity = 1, interactive = true, verticalFrame, options) {
25292
+ function drawScrollbars(ctx, layout, descriptors, borderColor, opacity = 1, interactive = true, verticalFrame, options, hover) {
24470
25293
  const alpha = Number.isFinite(opacity) ? Math.min(Math.max(opacity, 0), 1) : 1;
24471
25294
  if (alpha <= 1e-3) {
24472
25295
  return;
@@ -24491,7 +25314,8 @@ function drawScrollbars(ctx, layout, descriptors, borderColor, opacity = 1, inte
24491
25314
  descriptors,
24492
25315
  borderColor,
24493
25316
  interactive,
24494
- resolveCanvasScrollbarAxis(options, "horizontal")
25317
+ resolveCanvasScrollbarAxis(options, "horizontal"),
25318
+ hover
24495
25319
  );
24496
25320
  }
24497
25321
  if (layout.vertical) {
@@ -24502,7 +25326,8 @@ function drawScrollbars(ctx, layout, descriptors, borderColor, opacity = 1, inte
24502
25326
  descriptors,
24503
25327
  borderColor,
24504
25328
  interactive,
24505
- resolveCanvasScrollbarAxis(options, "vertical")
25329
+ resolveCanvasScrollbarAxis(options, "vertical"),
25330
+ hover
24506
25331
  );
24507
25332
  }
24508
25333
  if (layout.horizontal) {
@@ -24513,10 +25338,13 @@ function drawScrollbars(ctx, layout, descriptors, borderColor, opacity = 1, inte
24513
25338
  borderColor
24514
25339
  );
24515
25340
  }
25341
+ if (layout.vertical) {
25342
+ drawVerticalAxisFrame(ctx, layout.vertical, borderColor, verticalFrame);
25343
+ }
24516
25344
  ctx.restore();
24517
25345
  }
24518
25346
  function drawHorizontalScrollbarMask(ctx, layout, backgroundColor) {
24519
- const left = layout.decreaseButton.x;
25347
+ const left = 0;
24520
25348
  const right = layout.increaseButton.x + layout.increaseButton.width;
24521
25349
  const top = layout.decreaseButton.y;
24522
25350
  const height = layout.decreaseButton.height;
@@ -24529,7 +25357,7 @@ function drawHorizontalScrollbarMask(ctx, layout, backgroundColor) {
24529
25357
  ctx.restore();
24530
25358
  }
24531
25359
  function drawHorizontalScrollbarTopBorder(ctx, horizontal, vertical, borderColor) {
24532
- const left = Math.round(horizontal.decreaseButton.x) + 0.5;
25360
+ const left = 0.5;
24533
25361
  const horizontalRight = horizontal.increaseButton.x + horizontal.increaseButton.width;
24534
25362
  const verticalRight = vertical ? vertical.decreaseButton.x + vertical.decreaseButton.width : horizontalRight;
24535
25363
  const right = Math.round(Math.max(horizontalRight, verticalRight)) - 0.5;
@@ -24546,21 +25374,23 @@ function drawHorizontalScrollbarTopBorder(ctx, horizontal, vertical, borderColor
24546
25374
  ctx.stroke();
24547
25375
  ctx.restore();
24548
25376
  }
24549
- function drawAxisScrollbar(ctx, layout, axis, descriptors, borderColor, interactive, style) {
25377
+ function drawAxisScrollbar(ctx, layout, axis, descriptors, borderColor, interactive, style, hover) {
24550
25378
  const kind = axis === "horizontal" ? "horizontal-scrollbar" : "vertical-scrollbar";
24551
25379
  if (interactive) {
24552
- descriptors.push({
24553
- kind,
24554
- rect: layout.thumb,
24555
- columnKey: `__${axis}_scrollbar_thumb__`,
24556
- scrollbarRole: "thumb"
24557
- });
24558
- descriptors.push({
24559
- kind,
24560
- rect: layout.track,
24561
- columnKey: `__${axis}_scrollbar_track__`,
24562
- scrollbarRole: "track"
24563
- });
25380
+ if (style.mode === "scrollbar") {
25381
+ descriptors.push({
25382
+ kind,
25383
+ rect: layout.thumb,
25384
+ columnKey: `__${axis}_scrollbar_thumb__`,
25385
+ scrollbarRole: "thumb"
25386
+ });
25387
+ descriptors.push({
25388
+ kind,
25389
+ rect: layout.track,
25390
+ columnKey: `__${axis}_scrollbar_track__`,
25391
+ scrollbarRole: "track"
25392
+ });
25393
+ }
24564
25394
  descriptors.push({
24565
25395
  kind,
24566
25396
  rect: layout.decreaseButton,
@@ -24586,10 +25416,101 @@ function drawAxisScrollbar(ctx, layout, axis, descriptors, borderColor, interact
24586
25416
  }
24587
25417
  ctx.restore();
24588
25418
  }
25419
+ if (style.mode === "scrollbar") {
25420
+ const pressedTrack = hover?.pressedScrollbarPart?.axis === axis && hover.pressedScrollbarPart.role === "track";
25421
+ const hoveredTrack = hover?.area === `${axis}-scrollbar` && hover.scrollbarRole === "track";
25422
+ if (pressedTrack || hoveredTrack) {
25423
+ ctx.fillStyle = pressedTrack ? style.buttonPressedBackgroundColor : style.buttonHoverBackgroundColor;
25424
+ ctx.fillRect(
25425
+ layout.track.x,
25426
+ layout.track.y,
25427
+ layout.track.width,
25428
+ layout.track.height
25429
+ );
25430
+ }
25431
+ }
25432
+ for (const [role, rect] of [
25433
+ ["decrease-button", layout.decreaseButton],
25434
+ ["increase-button", layout.increaseButton]
25435
+ ]) {
25436
+ const pressed = hover?.pressedScrollbarButton?.axis === axis && hover.pressedScrollbarButton.role === role;
25437
+ const hovered = hover?.area === `${axis}-scrollbar` && hover.scrollbarRole === role;
25438
+ const background = pressed ? style.buttonPressedBackgroundColor : hovered ? style.buttonHoverBackgroundColor : style.buttonBackgroundColor;
25439
+ if (background) {
25440
+ ctx.fillStyle = background;
25441
+ ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
25442
+ }
25443
+ }
24589
25444
  drawButton(ctx, layout.decreaseButton, axis, "decrease", style.buttonColor);
24590
25445
  drawButton(ctx, layout.increaseButton, axis, "increase", style.buttonColor);
24591
- drawThumb(ctx, layout.thumb, style);
24592
- drawTrackBorder(ctx, layout.track, axis, borderColor);
25446
+ if (style.mode === "button") {
25447
+ drawButtonDivider(ctx, layout.increaseButton, axis, borderColor);
25448
+ if (axis === "horizontal") {
25449
+ drawButtonModeFrame(ctx, layout.decreaseButton, borderColor);
25450
+ }
25451
+ } else {
25452
+ const pressedThumb = hover?.pressedScrollbarPart?.axis === axis && hover.pressedScrollbarPart.role === "thumb";
25453
+ const hoveredThumb = hover?.area === `${axis}-scrollbar` && hover.scrollbarRole === "thumb";
25454
+ drawThumb(
25455
+ ctx,
25456
+ layout.thumb,
25457
+ style,
25458
+ pressedThumb ? style.buttonPressedBackgroundColor : hoveredThumb ? style.buttonHoverBackgroundColor : void 0
25459
+ );
25460
+ drawTrackBorder(ctx, layout.track, axis, borderColor);
25461
+ if (axis === "horizontal") {
25462
+ drawButtonModeFrame(ctx, layout.decreaseButton, borderColor);
25463
+ }
25464
+ }
25465
+ }
25466
+ function drawButtonModeFrame(ctx, first, borderColor) {
25467
+ const left = Math.round(first.x) + 0.5;
25468
+ const top = Math.round(first.y) + 0.5;
25469
+ ctx.save();
25470
+ ctx.strokeStyle = borderColor;
25471
+ ctx.lineWidth = 1;
25472
+ ctx.beginPath();
25473
+ ctx.moveTo(left, top);
25474
+ ctx.lineTo(left, Math.round(first.y + first.height) - 0.5);
25475
+ ctx.stroke();
25476
+ ctx.restore();
25477
+ }
25478
+ function drawVerticalAxisFrame(ctx, layout, borderColor, frame) {
25479
+ const first = layout.decreaseButton;
25480
+ const last = layout.increaseButton;
25481
+ const left = Math.round(first.x) + 0.5;
25482
+ const right = Math.round(first.x + first.width) - 0.5;
25483
+ const top = Math.round(frame?.top ?? first.y) + 0.5;
25484
+ const buttonTop = Math.round(first.y) + 0.5;
25485
+ const bottom = Math.round(frame ? frame.top + frame.height : last.y + last.height) - 0.5;
25486
+ if (right <= left || bottom <= top) return;
25487
+ ctx.save();
25488
+ ctx.strokeStyle = borderColor;
25489
+ ctx.lineWidth = 1;
25490
+ ctx.beginPath();
25491
+ ctx.moveTo(left, bottom);
25492
+ ctx.lineTo(left, top);
25493
+ ctx.moveTo(left, buttonTop);
25494
+ ctx.lineTo(right, buttonTop);
25495
+ ctx.stroke();
25496
+ ctx.restore();
25497
+ }
25498
+ function drawButtonDivider(ctx, second, axis, borderColor) {
25499
+ ctx.save();
25500
+ ctx.strokeStyle = borderColor;
25501
+ ctx.lineWidth = 1;
25502
+ ctx.beginPath();
25503
+ if (axis === "horizontal") {
25504
+ const x = Math.round(second.x) + 0.5;
25505
+ ctx.moveTo(x, second.y);
25506
+ ctx.lineTo(x, second.y + second.height);
25507
+ } else {
25508
+ const y = Math.round(second.y) + 0.5;
25509
+ ctx.moveTo(Math.round(second.x) + 0.5, y);
25510
+ ctx.lineTo(Math.round(second.x + second.width) - 0.5, y);
25511
+ }
25512
+ ctx.stroke();
25513
+ ctx.restore();
24593
25514
  }
24594
25515
  function drawTrackBorder(ctx, rect, axis, borderColor) {
24595
25516
  const left = Math.round(rect.x) + 0.5;
@@ -24651,7 +25572,7 @@ function drawVerticalScrollbarFrame(ctx, frame, borderColor) {
24651
25572
  }
24652
25573
  ctx.restore();
24653
25574
  }
24654
- function drawThumb(ctx, rect, style) {
25575
+ function drawThumb(ctx, rect, style, highlightColor) {
24655
25576
  ctx.save();
24656
25577
  ctx.fillStyle = style.thumbColor;
24657
25578
  roundRect2(
@@ -24663,6 +25584,18 @@ function drawThumb(ctx, rect, style) {
24663
25584
  style.thumbRadius ?? rect.height / 2
24664
25585
  );
24665
25586
  ctx.fill();
25587
+ if (highlightColor) {
25588
+ ctx.fillStyle = highlightColor;
25589
+ roundRect2(
25590
+ ctx,
25591
+ rect.x,
25592
+ rect.y,
25593
+ rect.width,
25594
+ rect.height,
25595
+ style.thumbRadius ?? rect.height / 2
25596
+ );
25597
+ ctx.fill();
25598
+ }
24666
25599
  ctx.restore();
24667
25600
  }
24668
25601
  function drawButton(ctx, rect, axis, direction, color) {
@@ -24994,6 +25927,7 @@ function drawListTableHeader(params) {
24994
25927
  const collapsedColumnMarkers = resolveCollapsedHeaderColumnMarkers({
24995
25928
  columns: options.columns,
24996
25929
  visibleColumnKeys: leafColumns.map((column) => column.key),
25930
+ showCollapsedColumnIcon: options.showCollapsedColumnIcon,
24997
25931
  // 系统列是否存在由功能配置决定,不属于用户隐藏的业务列,不能绘制恢复标记。
24998
25932
  excludedColumnKeys: [
24999
25933
  ...groupingColumnKeys ?? [],
@@ -25092,7 +26026,7 @@ function resolveActiveCellOverlayLayout(params) {
25092
26026
  highlightMode: params.highlightMode,
25093
26027
  columnKeys: params.columnKeys ?? [],
25094
26028
  allowColumnRange: selection.rowIndex == null,
25095
- allowRowRange: selection.columnKey === ROW_SELECTOR_COLUMN_KEY,
26029
+ allowRowRange: selection.columnKey === ROW_SELECTOR_COLUMN_KEY || params.rangeHighlight?.selectedRowRanges != null || params.rangeHighlight?.selectedCellRanges != null && params.rangeHighlight.selectedRowRange != null,
25096
26030
  resolveClipRect: (item) => resolveActiveCellSectionClipRect(item, params),
25097
26031
  width: params.width,
25098
26032
  height: params.height
@@ -25183,10 +26117,13 @@ function drawActiveCellOverlay(params) {
25183
26117
  }
25184
26118
  function resolveRangeHighlightLayouts(params) {
25185
26119
  const rowRange = params.rangeHighlight?.selectedRowRange;
26120
+ const rowRanges = params.rangeHighlight?.selectedRowRanges ?? (rowRange ? [rowRange] : []);
25186
26121
  const columnRange = params.rangeHighlight?.selectedColumnRange;
26122
+ const selectedColumnKeys = params.rangeHighlight?.selectedColumnKeys;
25187
26123
  const cellRange = params.rangeHighlight?.selectedCellRange;
25188
- const rowSelectorRange = rowRange && params.allowRowRange;
25189
- if (!cellRange && !rowSelectorRange && (!columnRange || !params.allowColumnRange)) {
26124
+ const cellRanges = params.rangeHighlight?.selectedCellRanges ?? (cellRange ? [cellRange] : []);
26125
+ const rowSelectorRange = rowRanges.length > 0 && params.allowRowRange;
26126
+ if (cellRanges.length === 0 && !rowSelectorRange && (!(columnRange || selectedColumnKeys?.length) || !params.allowColumnRange)) {
25190
26127
  return { rects: [], segments: [] };
25191
26128
  }
25192
26129
  const bodyDescriptors = params.descriptors.filter(
@@ -25195,20 +26132,33 @@ function resolveRangeHighlightLayouts(params) {
25195
26132
  const selected = bodyDescriptors.filter((item) => {
25196
26133
  const itemRowStart = item.rowIndex;
25197
26134
  const itemRowEnd = itemRowStart + Math.max(item.rowSpan ?? 1, 1) - 1;
25198
- const rowSelected = rowRange != null && itemRowEnd >= rowRange.start && itemRowStart <= rowRange.end;
26135
+ const rowSelected = rowRanges.some(
26136
+ (range) => itemRowEnd >= range.start && itemRowStart <= range.end
26137
+ );
25199
26138
  const columnIndex = params.columnKeys.indexOf(item.columnKey);
25200
- const columnSelected = columnRange != null && columnIndex >= columnRange.start && columnIndex <= columnRange.end;
25201
- if (cellRange) {
25202
- return itemRowEnd >= cellRange.startRowIndex && itemRowStart <= cellRange.endRowIndex && columnIndex >= cellRange.startColumnIndex && columnIndex <= cellRange.endColumnIndex;
25203
- }
25204
- if (rowSelectorRange) {
25205
- return rowSelected;
25206
- }
25207
- return params.allowColumnRange && columnSelected;
26139
+ const columnSelected = selectedColumnKeys != null ? selectedColumnKeys.includes(item.columnKey) : columnRange != null && columnIndex >= columnRange.start && columnIndex <= columnRange.end;
26140
+ const cellSelected = cellRanges.some(
26141
+ (range) => itemRowEnd >= range.startRowIndex && itemRowStart <= range.endRowIndex && columnIndex >= range.startColumnIndex && columnIndex <= range.endColumnIndex
26142
+ );
26143
+ return cellSelected || rowSelectorRange && rowSelected || params.allowColumnRange && columnSelected;
25208
26144
  });
25209
26145
  const groups = /* @__PURE__ */ new Map();
26146
+ const selectedKeySet = new Set(selectedColumnKeys ?? []);
25210
26147
  selected.forEach((descriptor) => {
25211
- const groupKey = cellRange || rowSelectorRange ? `${descriptor.fixed ?? "center"}:${descriptor.frozen ? "frozen" : "scroll"}` : `column:${descriptor.fixed ?? "center"}:${descriptor.frozen ? "frozen" : "scroll"}`;
26148
+ const columnIndex = params.columnKeys.indexOf(descriptor.columnKey);
26149
+ let runStart = columnIndex;
26150
+ if (selectedColumnKeys != null) {
26151
+ while (runStart > 0 && selectedKeySet.has(params.columnKeys[runStart - 1])) {
26152
+ runStart--;
26153
+ }
26154
+ }
26155
+ const cellRangeIndex = cellRanges.findIndex(
26156
+ (range) => descriptor.rowIndex >= range.startRowIndex && descriptor.rowIndex <= range.endRowIndex && columnIndex >= range.startColumnIndex && columnIndex <= range.endColumnIndex
26157
+ );
26158
+ const rowRangeIndex = rowRanges.findIndex(
26159
+ (range) => descriptor.rowIndex >= range.start && descriptor.rowIndex <= range.end
26160
+ );
26161
+ const groupKey = rowSelectorRange && rowRangeIndex >= 0 ? `row:${rowRangeIndex}:${descriptor.fixed ?? "center"}:${descriptor.frozen ? "frozen" : "scroll"}` : cellRangeIndex >= 0 ? `cell:${cellRangeIndex}:${descriptor.fixed ?? "center"}:${descriptor.frozen ? "frozen" : "scroll"}` : `column:${selectedColumnKeys != null ? runStart : "range"}:${descriptor.fixed ?? "center"}:${descriptor.frozen ? "frozen" : "scroll"}`;
25212
26162
  const current = groups.get(groupKey);
25213
26163
  const rect = current ? {
25214
26164
  x: Math.min(current.rect.x, descriptor.rect.x),
@@ -25243,8 +26193,8 @@ function resolveRangeHighlightLayouts(params) {
25243
26193
  );
25244
26194
  return {
25245
26195
  ...range,
25246
- omitLeft: range.rect.x > minX,
25247
- omitRight: range.rect.x + range.rect.width < maxX
26196
+ omitLeft: selectedColumnKeys == null && range.rect.x > minX,
26197
+ omitRight: selectedColumnKeys == null && range.rect.x + range.rect.width < maxX
25248
26198
  };
25249
26199
  });
25250
26200
  const rangeSegments = resolveRangeBorderSegments(
@@ -25761,7 +26711,8 @@ function executeListTableRenderPipeline(params) {
25761
26711
  headerBackgroundColor: theme.headerBackgroundColor,
25762
26712
  bodyBackgroundColor: theme.backgroundColor
25763
26713
  },
25764
- options.scrollbar
26714
+ options.scrollbar,
26715
+ hover
25765
26716
  );
25766
26717
  drawActiveCellOverlay({
25767
26718
  ctx,
@@ -25814,8 +26765,8 @@ function drawGroupingBar(params) {
25814
26765
  ctx.fillRect(0, 0, width, height);
25815
26766
  ctx.strokeStyle = theme.borderColor;
25816
26767
  ctx.beginPath();
25817
- ctx.moveTo(0, height - 0.5);
25818
- ctx.lineTo(width, height - 0.5);
26768
+ ctx.moveTo(0, height + 0.5);
26769
+ ctx.lineTo(width, height + 0.5);
25819
26770
  ctx.stroke();
25820
26771
  ctx.fillStyle = theme.headerTextColor;
25821
26772
  ctx.font = `${theme.headerFontWeight} ${theme.fontSize}px ${theme.fontFamily}`;
@@ -25907,6 +26858,16 @@ function drawColumnResizeIndicator(params) {
25907
26858
  // src/services/image-clipboard-service.ts
25908
26859
  var MAX_IMAGE_SIDE = 16384;
25909
26860
  var MAX_IMAGE_PIXELS = 16e6;
26861
+ function collectSelectedIndices(ranges, count) {
26862
+ const indices = /* @__PURE__ */ new Set();
26863
+ for (const range of ranges) {
26864
+ for (let index = Math.max(range.start, 0); index <= Math.min(range.end, count - 1); index++) {
26865
+ indices.add(index);
26866
+ if (indices.size > MAX_IMAGE_SIDE) return null;
26867
+ }
26868
+ }
26869
+ return [...indices].sort((left, right) => left - right);
26870
+ }
25910
26871
  function assertTableImageSize(width, height) {
25911
26872
  if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
25912
26873
  throw new Error("\u6CA1\u6709\u53EF\u590D\u5236\u7684\u8868\u683C\u533A\u57DF\u3002");
@@ -25917,8 +26878,96 @@ function assertTableImageSize(width, height) {
25917
26878
  }
25918
26879
  function resolveImageSelection(host) {
25919
26880
  const state = host.rangeHighlight;
25920
- if (state.selectedCellRange) return state.selectedCellRange;
25921
26881
  const rowCount = host.getDisplayData().length;
26882
+ const columnCount = host.leafColumns.length;
26883
+ if (state.selectedCellRanges != null) {
26884
+ const rowRanges = state.selectedRowRanges ?? (state.selectedRowRange ? [state.selectedRowRange] : []);
26885
+ if (!state.selectedCellRanges.length && !rowRanges.length) return null;
26886
+ const rowIndices = collectSelectedIndices(
26887
+ [
26888
+ ...state.selectedCellRanges.map((range) => ({
26889
+ start: range.startRowIndex,
26890
+ end: range.endRowIndex
26891
+ })),
26892
+ ...rowRanges
26893
+ ],
26894
+ rowCount
26895
+ );
26896
+ if (rowIndices === null) {
26897
+ return {
26898
+ startRowIndex: 0,
26899
+ endRowIndex: rowCount - 1,
26900
+ startColumnIndex: 0,
26901
+ endColumnIndex: columnCount - 1,
26902
+ tooLarge: true
26903
+ };
26904
+ }
26905
+ const columnIndices = collectSelectedIndices(
26906
+ rowRanges.length ? [{ start: 0, end: columnCount - 1 }] : state.selectedCellRanges.map((range) => ({
26907
+ start: range.startColumnIndex,
26908
+ end: range.endColumnIndex
26909
+ })),
26910
+ columnCount
26911
+ );
26912
+ if (columnIndices === null) {
26913
+ return {
26914
+ startRowIndex: 0,
26915
+ endRowIndex: rowCount - 1,
26916
+ startColumnIndex: 0,
26917
+ endColumnIndex: columnCount - 1,
26918
+ tooLarge: true
26919
+ };
26920
+ }
26921
+ if (!rowIndices.length || !columnIndices.length) return null;
26922
+ return {
26923
+ startRowIndex: rowIndices[0],
26924
+ endRowIndex: rowIndices[rowIndices.length - 1],
26925
+ startColumnIndex: columnIndices[0],
26926
+ endColumnIndex: columnIndices[columnIndices.length - 1],
26927
+ rowIndices,
26928
+ columnIndices,
26929
+ cellRanges: state.selectedCellRanges,
26930
+ rowRanges
26931
+ };
26932
+ }
26933
+ if (state.selectedCellRange) return state.selectedCellRange;
26934
+ if (state.selectedColumnKeys != null) {
26935
+ const columnIndices = host.leafColumns.flatMap(
26936
+ (column, index) => state.selectedColumnKeys?.includes(column.key) ? [index] : []
26937
+ );
26938
+ if (!columnIndices.length || !rowCount) return null;
26939
+ return {
26940
+ startRowIndex: 0,
26941
+ endRowIndex: rowCount - 1,
26942
+ startColumnIndex: columnIndices[0],
26943
+ endColumnIndex: columnIndices[columnIndices.length - 1],
26944
+ columnIndices
26945
+ };
26946
+ }
26947
+ if (state.selectedRowRanges != null) {
26948
+ if (!state.selectedRowRanges.length) return null;
26949
+ const rowIndices = collectSelectedIndices(
26950
+ state.selectedRowRanges,
26951
+ rowCount
26952
+ );
26953
+ if (rowIndices === null) {
26954
+ return {
26955
+ startRowIndex: state.selectedRowRanges[0].start,
26956
+ endRowIndex: state.selectedRowRanges[0].end,
26957
+ startColumnIndex: 0,
26958
+ endColumnIndex: columnCount - 1,
26959
+ tooLarge: true
26960
+ };
26961
+ }
26962
+ if (!rowIndices.length || !columnCount) return null;
26963
+ return {
26964
+ startRowIndex: rowIndices[0],
26965
+ endRowIndex: rowIndices[rowIndices.length - 1],
26966
+ startColumnIndex: 0,
26967
+ endColumnIndex: columnCount - 1,
26968
+ rowIndices
26969
+ };
26970
+ }
25922
26971
  const columnIndex = host.leafColumns.findIndex(
25923
26972
  (column) => column.key === host.selection.columnKey
25924
26973
  );
@@ -25934,7 +26983,7 @@ function resolveImageSelection(host) {
25934
26983
  startRowIndex: state.selectedRowRange.start,
25935
26984
  endRowIndex: state.selectedRowRange.end,
25936
26985
  startColumnIndex: 0,
25937
- endColumnIndex: host.leafColumns.length - 1
26986
+ endColumnIndex: columnCount - 1
25938
26987
  };
25939
26988
  if (host.selection.rowIndex != null && columnIndex >= 0)
25940
26989
  return {
@@ -25966,23 +27015,50 @@ function renderTableCopyImage(host, scope) {
25966
27015
  const range = scope === "selection" ? resolveImageSelection(host) : null;
25967
27016
  if (scope === "selection" && !range)
25968
27017
  throw new Error("\u8BF7\u5148\u9009\u4E2D\u9700\u8981\u590D\u5236\u7684\u5355\u5143\u683C\u533A\u57DF\u3002");
27018
+ if (range?.tooLarge)
27019
+ throw new Error("\u56FE\u7247\u533A\u57DF\u8FC7\u5927\uFF0C\u8BF7\u7F29\u5C0F\u9009\u533A\u6216\u9009\u62E9\u201C\u89C6\u53E3\u533A\u57DF\u201D\u3002");
25969
27020
  const startRow = range ? Math.max(Math.min(range.startRowIndex, range.endRowIndex), 0) : 0;
25970
27021
  const endRow = range ? Math.max(range.startRowIndex, range.endRowIndex) : current.baseRows.length - 1;
25971
27022
  const startColumn = range ? Math.max(Math.min(range.startColumnIndex, range.endColumnIndex), 0) : 0;
25972
27023
  const endColumn = range ? Math.max(range.startColumnIndex, range.endColumnIndex) : current.leafColumns.length - 1;
25973
- const columns = current.leafColumns.slice(startColumn, endColumn + 1);
27024
+ if (range && ((range.rowIndices?.length ?? endRow - startRow + 1) > MAX_IMAGE_SIDE || (range.columnIndices?.length ?? endColumn - startColumn + 1) > MAX_IMAGE_SIDE)) {
27025
+ throw new Error("\u56FE\u7247\u533A\u57DF\u8FC7\u5927\uFF0C\u8BF7\u7F29\u5C0F\u9009\u533A\u6216\u9009\u62E9\u201C\u89C6\u53E3\u533A\u57DF\u201D\u3002");
27026
+ }
27027
+ const selectedRowIndices = range?.rowIndices ?? (range ? Array.from(
27028
+ { length: endRow - startRow + 1 },
27029
+ (_, index) => startRow + index
27030
+ ) : null);
27031
+ const selectedColumnIndices = range?.columnIndices ?? (range ? Array.from(
27032
+ { length: endColumn - startColumn + 1 },
27033
+ (_, index) => startColumn + index
27034
+ ) : null);
27035
+ const columns = selectedColumnIndices ? selectedColumnIndices.map((index) => current.leafColumns[index]) : current.leafColumns;
25974
27036
  const width = columns.reduce((total, column) => total + column.width, 0);
25975
- const rowCount = range ? endRow - startRow + 1 : current.baseRows.length;
27037
+ const rowCount = selectedRowIndices?.length ?? current.baseRows.length;
25976
27038
  const dpr = source.ownerDocument.defaultView?.devicePixelRatio || 1;
25977
27039
  const zoom = host.tableZoom || 1;
25978
27040
  assertTableImageSize(
25979
27041
  Math.ceil(width * zoom * dpr),
25980
27042
  Math.ceil(Math.max(rowCount, 1) * current.rowHeight * zoom * dpr)
25981
27043
  );
25982
- const rows = range ? current.displayRows.slice(startRow, endRow + 1) : current.baseRows;
27044
+ const rows = selectedRowIndices ? selectedRowIndices.map((index) => current.displayRows[index]) : current.baseRows;
25983
27045
  const keys = new Set(columns.map((column) => column.key));
25984
27046
  if (!range) state?.groupColumnKeys.forEach((key) => keys.add(key));
25985
27047
  const widths = new Map(columns.map((column) => [column.key, column.width]));
27048
+ const originalColumnIndices = new Map(
27049
+ current.leafColumns.map((column, index) => [column.key, index])
27050
+ );
27051
+ const isCellSelected = (rowIndex, columnKey) => {
27052
+ if (!range?.cellRanges) return true;
27053
+ if (range.rowRanges?.some(
27054
+ (rowRange) => rowIndex >= rowRange.start && rowIndex <= rowRange.end
27055
+ ))
27056
+ return true;
27057
+ const columnIndex = originalColumnIndices.get(columnKey);
27058
+ return columnIndex != null && range.cellRanges.some(
27059
+ (cellRange) => rowIndex >= cellRange.startRowIndex && rowIndex <= cellRange.endRowIndex && columnIndex >= cellRange.startColumnIndex && columnIndex <= cellRange.endColumnIndex
27060
+ );
27061
+ };
25986
27062
  const cloneColumns2 = (items) => items.flatMap((column) => {
25987
27063
  const children = column.children ? cloneColumns2(column.children) : void 0;
25988
27064
  if (children ? !children.length : !keys.has(String(column.key)))
@@ -25995,8 +27071,21 @@ function renderTableCopyImage(host, scope) {
25995
27071
  children,
25996
27072
  fixed: void 0,
25997
27073
  width: widths.get(String(column.key)) ?? column.width,
25998
- onCell: onCell && range ? (value, record, index, context) => onCell(value, record, index + startRow, context) : onCell,
25999
- render: render && range ? (value, record, index, context) => render(value, record, index + startRow, context) : render
27074
+ onCell: onCell && range ? (value, record, index, context) => onCell(
27075
+ value,
27076
+ record,
27077
+ selectedRowIndices?.[index] ?? index + startRow,
27078
+ context
27079
+ ) : onCell,
27080
+ render: range?.cellRanges && !children ? (value, record, index, context) => {
27081
+ const sourceRowIndex = selectedRowIndices?.[index] ?? index + startRow;
27082
+ return isCellSelected(sourceRowIndex, String(column.key)) ? render?.(value, record, sourceRowIndex, context) ?? null : "";
27083
+ } : render && range ? (value, record, index, context) => render(
27084
+ value,
27085
+ record,
27086
+ selectedRowIndices?.[index] ?? index + startRow,
27087
+ context
27088
+ ) : render
26000
27089
  }
26001
27090
  ];
26002
27091
  });
@@ -26085,7 +27174,7 @@ function renderTableCopyImage(host, scope) {
26085
27174
  fixedLeftBoundarySkips: [],
26086
27175
  getNestedTableHighlight: (params) => host.animationController.getNestedTableHighlight({
26087
27176
  ...params,
26088
- rowIndex: params.rowIndex + startRow
27177
+ rowIndex: selectedRowIndices?.[params.rowIndex] ?? params.rowIndex + startRow
26089
27178
  })
26090
27179
  });
26091
27180
  return canvas;
@@ -26535,6 +27624,7 @@ function buildHeaderDataIndexOptions(rows, columns) {
26535
27624
 
26536
27625
  // src/features/overlay/context-menu-builder.ts
26537
27626
  function createListTableContextMenuActions(params) {
27627
+ const getExportColumns = () => params.getExportColumns?.() ?? params.getColumns();
26538
27628
  return {
26539
27629
  onCopyHeaderCell: (columnKey) => {
26540
27630
  params.hideMenu();
@@ -26590,50 +27680,82 @@ function createListTableContextMenuActions(params) {
26590
27680
  onExportJson: () => {
26591
27681
  params.hideMenu();
26592
27682
  params.startExportTask(
26593
- (fileName) => exportAllRowsJsonContent({
27683
+ (fileName, settings) => exportAllRowsJsonContent({
26594
27684
  fileName,
26595
27685
  rows: params.getAllRows(),
26596
- columns: params.getColumns()
27686
+ columns: getExportColumns(),
27687
+ settings
26597
27688
  }),
26598
27689
  "\u6B63\u5728\u5BFC\u51FA JSON\u2026",
26599
- buildTableExportFileName("json")
27690
+ buildTableExportFileName("json"),
27691
+ {
27692
+ columns: getListTableExportColumnChoices(
27693
+ getExportColumns(),
27694
+ params.getExportSortState?.()
27695
+ ),
27696
+ includeSummary: params.getExportSummaryEnabled?.() ?? false
27697
+ }
26600
27698
  );
26601
27699
  },
26602
27700
  onExportCsv: () => {
26603
27701
  params.hideMenu();
26604
27702
  params.startExportTask(
26605
- (fileName) => exportAllRowsCsvContent({
27703
+ (fileName, settings) => exportAllRowsCsvContent({
26606
27704
  fileName,
26607
27705
  rows: params.getAllRows(),
26608
- columns: params.getColumns()
27706
+ columns: getExportColumns(),
27707
+ settings
26609
27708
  }),
26610
27709
  "\u6B63\u5728\u5BFC\u51FA CSV\u2026",
26611
- buildTableExportFileName("csv")
27710
+ buildTableExportFileName("csv"),
27711
+ {
27712
+ columns: getListTableExportColumnChoices(
27713
+ getExportColumns(),
27714
+ params.getExportSortState?.()
27715
+ ),
27716
+ includeSummary: params.getExportSummaryEnabled?.() ?? false
27717
+ }
26612
27718
  );
26613
27719
  },
26614
27720
  onExportTxt: () => {
26615
27721
  params.hideMenu();
26616
27722
  params.startExportTask(
26617
- (fileName) => exportAllRowsTxtContent({
27723
+ (fileName, settings) => exportAllRowsTxtContent({
26618
27724
  fileName,
26619
27725
  rows: params.getAllRows(),
26620
- columns: params.getColumns()
27726
+ columns: getExportColumns(),
27727
+ settings
26621
27728
  }),
26622
27729
  "\u6B63\u5728\u5BFC\u51FA TXT\u2026",
26623
- buildTableExportFileName("txt")
27730
+ buildTableExportFileName("txt"),
27731
+ {
27732
+ columns: getListTableExportColumnChoices(
27733
+ getExportColumns(),
27734
+ params.getExportSortState?.()
27735
+ ),
27736
+ includeSummary: params.getExportSummaryEnabled?.() ?? false
27737
+ }
26624
27738
  );
26625
27739
  },
26626
27740
  onExportXlsx: () => {
26627
27741
  params.hideMenu();
26628
27742
  params.startExportTask(
26629
- (fileName) => exportAllRowsXlsxContent({
27743
+ (fileName, settings) => exportAllRowsXlsxContent({
26630
27744
  includeSummary: params.getExportSummaryEnabled?.() ?? false,
26631
27745
  fileName,
26632
27746
  rows: params.getAllRows(),
26633
- columns: params.getColumns()
27747
+ columns: getExportColumns(),
27748
+ settings
26634
27749
  }),
26635
27750
  "\u6B63\u5728\u5BFC\u51FA XLSX\u2026",
26636
- buildTableExportFileName("xlsx")
27751
+ buildTableExportFileName("xlsx"),
27752
+ {
27753
+ columns: getListTableExportColumnChoices(
27754
+ getExportColumns(),
27755
+ params.getExportSortState?.()
27756
+ ),
27757
+ includeSummary: params.getExportSummaryEnabled?.() ?? false
27758
+ }
26637
27759
  );
26638
27760
  },
26639
27761
  onFreezeRow: params.onFreezeRow,
@@ -26788,6 +27910,7 @@ function buildListTableContextMenuConfig(params) {
26788
27910
  const enabledFeatures = resolveEnabledContextMenuFeatures(contextMenu);
26789
27911
  const isTableSettingsArea = isHeaderArea || isExpandedArea;
26790
27912
  const isBodyArea = bodyRowIndex != null;
27913
+ const canResetTable = isTableSettingsArea || isBodyArea;
26791
27914
  const isSelectionColumn = columnKey === ROW_SELECTION_COLUMN_KEY || columnKey === ROW_SELECTOR_COLUMN_KEY;
26792
27915
  const enableCopy = enabledFeatures.has("copy");
26793
27916
  const enableChart = enabledFeatures.has("chart");
@@ -26906,19 +28029,19 @@ function buildListTableContextMenuConfig(params) {
26906
28029
  onUnfreezeRow: enableFreeze && isBodyArea && frozenRowPosition != null ? () => {
26907
28030
  actions.onUnfreezeRow(bodyRowIndex);
26908
28031
  } : void 0,
26909
- onResetFilter: enableReset && isTableSettingsArea ? actions.onResetFilter : void 0,
26910
- onResetSort: enableReset && isTableSettingsArea ? actions.onResetSort : void 0,
28032
+ onResetFilter: enableReset && canResetTable ? actions.onResetFilter : void 0,
28033
+ onResetSort: enableReset && canResetTable ? actions.onResetSort : void 0,
26911
28034
  onSortAscend: canSortCurrentColumn && actions.onSortAscend ? () => actions.onSortAscend?.(columnKey) : void 0,
26912
28035
  onSortDescend: canSortCurrentColumn && actions.onSortDescend ? () => actions.onSortDescend?.(columnKey) : void 0,
26913
28036
  onClearSort: canSortCurrentColumn && actions.onClearSort ? () => actions.onClearSort?.(columnKey) : void 0,
26914
28037
  onFixLeft: enableFreeze && isHeaderArea && !isSelectionColumn && actions.onFixLeft ? () => actions.onFixLeft?.(columnKey) : void 0,
26915
28038
  onFixRight: enableFreeze && isHeaderArea && !isSelectionColumn && actions.onFixRight ? () => actions.onFixRight?.(columnKey) : void 0,
26916
28039
  onUnfix: enableFreeze && isHeaderArea && !isSelectionColumn && actions.onUnfix ? () => actions.onUnfix?.(columnKey) : void 0,
26917
- onResetHeader: enableReset && isTableSettingsArea ? actions.onResetHeader : void 0,
26918
- onResetGrouping: enableReset && isTableSettingsArea ? actions.onResetGrouping : void 0,
26919
- onResetSummary: enableReset && isTableSettingsArea ? actions.onResetSummary : void 0,
26920
- onResetAlignment: enableReset && isTableSettingsArea ? actions.onResetAlignment : void 0,
26921
- onResetDataFormat: enableReset && isTableSettingsArea ? actions.onResetDataFormat : void 0,
28040
+ onResetHeader: enableReset && canResetTable ? actions.onResetHeader : void 0,
28041
+ onResetGrouping: enableReset && canResetTable ? actions.onResetGrouping : void 0,
28042
+ onResetSummary: enableReset && canResetTable ? actions.onResetSummary : void 0,
28043
+ onResetAlignment: enableReset && canResetTable ? actions.onResetAlignment : void 0,
28044
+ onResetDataFormat: enableReset && canResetTable ? actions.onResetDataFormat : void 0,
26922
28045
  onAutoFitCurrentColumn: enableColumnWidth && isHeaderArea && !isSelectionColumn && actions.onAutoFitCurrentColumn ? () => actions.onAutoFitCurrentColumn?.(columnKey) : void 0,
26923
28046
  onAutoFitAllColumns: enableColumnWidth && isTableSettingsArea && !isSelectionColumn && actions.onAutoFitAllColumns ? actions.onAutoFitAllColumns : void 0,
26924
28047
  onAutoFitFillContainer: enableColumnWidth && isTableSettingsArea && !isSelectionColumn && actions.onAutoFitFillContainer ? actions.onAutoFitFillContainer : void 0,
@@ -27159,6 +28282,8 @@ function showHeaderContextMenu(params) {
27159
28282
  onChangeSummaryShowTypePrefix,
27160
28283
  onChangeColumnSettingsCache,
27161
28284
  onChangeCachePreference,
28285
+ onChangeScrollbar,
28286
+ onResetScrollbar,
27162
28287
  summaryVisible,
27163
28288
  getSelectionRange,
27164
28289
  onCopySelection,
@@ -27172,6 +28297,40 @@ function showHeaderContextMenu(params) {
27172
28297
  const isExpandedArea = result.area === "expanded-row" || result.columnKey === "__expanded_row__";
27173
28298
  const isSelectionColumn = result.columnKey === ROW_SELECTION_COLUMN_KEY || result.columnKey === ROW_SELECTOR_COLUMN_KEY;
27174
28299
  const isChartCorner = isHeaderArea && result.columnKey === ROW_SELECTOR_COLUMN_KEY && resolveEnabledContextMenuFeatures(options.contextMenu).has("chart");
28300
+ if (result.area === "horizontal-scrollbar" || result.area === "vertical-scrollbar") {
28301
+ if (options.contextMenu === false) {
28302
+ headerContextMenu.hide();
28303
+ return false;
28304
+ }
28305
+ event.preventDefault();
28306
+ filterPanel.hide();
28307
+ fixedPopup.hide();
28308
+ hideBodyTooltip();
28309
+ headerContextMenu.show({
28310
+ x: event.clientX,
28311
+ y: event.clientY,
28312
+ scrollbarArea: true,
28313
+ scrollbarRowCount: getRows().length,
28314
+ scrollbarColumnCount: params.scrollbarColumnCount ?? getColumns().length,
28315
+ onScrollToPosition: params.onScrollToPosition,
28316
+ onResetFilter,
28317
+ onResetSort,
28318
+ onResetHeader,
28319
+ onResetGrouping,
28320
+ onResetSummary,
28321
+ onResetAlignment,
28322
+ onResetDataFormat,
28323
+ scrollbar: options.scrollbar,
28324
+ onChangeScrollbar,
28325
+ onResetScrollbar,
28326
+ columnSettingsCacheAvailable: Boolean(options.storageKey),
28327
+ cacheColumnSettings: options.cacheColumnSettings,
28328
+ cachePreferences: options.cachePreferences,
28329
+ onChangeCachePreference,
28330
+ onClose
28331
+ });
28332
+ return true;
28333
+ }
27175
28334
  if (!isHeaderArea && !isBodyArea && !groupingBarArea && !isExpandedArea || !result.columnKey && !groupingBarArea && !isExpandedArea || isHeaderArea && isSelectionColumn && !isChartCorner) {
27176
28335
  headerContextMenu.hide();
27177
28336
  return false;
@@ -27193,8 +28352,8 @@ function showHeaderContextMenu(params) {
27193
28352
  onSelectBodyRow?.(bodyRowIndex, contextColumnKey);
27194
28353
  }
27195
28354
  const frozenRowPosition = bodyRowIndex == null ? null : getFrozenRowPosition2(bodyRowIndex);
27196
- headerContextMenu.show(
27197
- buildListTableContextMenuConfig({
28355
+ headerContextMenu.show({
28356
+ ...buildListTableContextMenuConfig({
27198
28357
  storageKey: options.storageKey,
27199
28358
  cacheColumnSettings: options.cacheColumnSettings,
27200
28359
  cachePreferences: options.cachePreferences,
@@ -27226,9 +28385,11 @@ function showHeaderContextMenu(params) {
27226
28385
  columnCount: getColumns().length,
27227
28386
  actions: createListTableContextMenuActions({
27228
28387
  getExportSummaryEnabled: params.getExportSummaryEnabled,
28388
+ getExportSortState: params.getExportSortState,
27229
28389
  getRows,
27230
28390
  getAllRows,
27231
28391
  getColumns,
28392
+ getExportColumns: params.getExportColumns,
27232
28393
  getHeaderTree,
27233
28394
  hideMenu: () => {
27234
28395
  headerContextMenu.hide();
@@ -27280,8 +28441,15 @@ function showHeaderContextMenu(params) {
27280
28441
  onOpenSearch,
27281
28442
  onCopyCustomSelection
27282
28443
  })
27283
- })
27284
- );
28444
+ }),
28445
+ sortState: params.getExportSortState?.() ?? [],
28446
+ scrollbarRowCount: getRows().length,
28447
+ scrollbarColumnCount: params.scrollbarColumnCount ?? getColumns().length,
28448
+ onScrollToPosition: params.onScrollToPosition,
28449
+ scrollbar: options.scrollbar,
28450
+ onChangeScrollbar,
28451
+ onResetScrollbar
28452
+ });
27285
28453
  return true;
27286
28454
  }
27287
28455
  function resolveContextMenuDensity(rowHeight) {
@@ -27309,7 +28477,9 @@ function createListTableChartData(params) {
27309
28477
  rowIndex,
27310
28478
  selectionRange,
27311
28479
  selectedRowRange,
27312
- selectedColumnRange
28480
+ selectedColumnRange,
28481
+ selectedColumnKeys,
28482
+ getRowKey: getRowKey2
27313
28483
  } = params;
27314
28484
  const startRow = Math.max(
27315
28485
  selectionRange?.startRowIndex ?? selectedRowRange?.start ?? Math.max((rowIndex ?? 0) - 10, 0),
@@ -27322,7 +28492,7 @@ function createListTableChartData(params) {
27322
28492
  const selectedColumns = selectionRange ? columns.slice(
27323
28493
  Math.max(selectionRange.startColumnIndex, 0),
27324
28494
  selectionRange.endColumnIndex + 1
27325
- ) : selectedRowRange ? columns : selectedColumnRange ? columns.slice(
28495
+ ) : selectedRowRange ? columns : selectedColumnKeys != null ? columns.filter((column) => selectedColumnKeys.includes(column.key)) : selectedColumnRange ? columns.slice(
27326
28496
  Math.max(selectedColumnRange.start, 0),
27327
28497
  selectedColumnRange.end + 1
27328
28498
  ) : columns.filter((column) => column.key === columnKey);
@@ -27361,7 +28531,8 @@ function createListTableChartData(params) {
27361
28531
  const labels = sampledRows.map(
27362
28532
  (_, index) => labelIndex >= 0 ? values[labelIndex]?.[index] || String(startRow + index + 1) : String(startRow + index + 1)
27363
28533
  );
27364
- return { labels, series: numericColumns };
28534
+ const keys = getRowKey2 ? sampledRows.map((record, index) => getRowKey2(record, startRow + index)) : void 0;
28535
+ return { labels, ...keys ? { keys } : {}, series: numericColumns };
27365
28536
  }
27366
28537
  function parseChartNumber(value) {
27367
28538
  const normalized = value.trim().replace(/[,,\s¥¥$]/g, "");
@@ -27374,6 +28545,9 @@ function parseChartNumber(value) {
27374
28545
  // src/features/tooltip/tooltip-feature.ts
27375
28546
  function getHeaderActionTooltipText(result, sortState) {
27376
28547
  const area = result.area;
28548
+ if (result.debugNodeType === "header-edit-icon" || result.debugNodeType === "nested-table-header-edit-icon") {
28549
+ return "\u5F53\u524D\u5217\u53EF\u7F16\u8F91";
28550
+ }
27377
28551
  if (area !== "sort-trigger" && area !== "filter-trigger" && area !== "fixed-trigger") {
27378
28552
  return null;
27379
28553
  }
@@ -28418,6 +29592,8 @@ var ListTableEventController = class {
28418
29592
  __publicField(this, "cellSelectionAutoScrollVelocity", { x: 0, y: 0 });
28419
29593
  __publicField(this, "cellSelectionAutoScrollTargetVelocity", { x: 0, y: 0 });
28420
29594
  __publicField(this, "continuousScrollTimer", null);
29595
+ __publicField(this, "scrollbarButtonFeedbackTimer", null);
29596
+ __publicField(this, "scrollbarPartFeedbackTimer", null);
28421
29597
  __publicField(this, "pendingEditableCellRowSelectionTimer", null);
28422
29598
  __publicField(this, "outsideClickDocument", null);
28423
29599
  __publicField(this, "outsideClickStarted", null);
@@ -28428,7 +29604,13 @@ var ListTableEventController = class {
28428
29604
  __publicField(this, "handleDocumentClick", (event) => {
28429
29605
  const startedOutside = this.outsideClickStarted ?? !this.isEventTargetInsideTable(event.target);
28430
29606
  this.outsideClickStarted = null;
28431
- if (!startedOutside || !this.host.selection.textSelection) return;
29607
+ if (!startedOutside) return;
29608
+ if (this.host.options.clearSelectionOnClick?.outside) {
29609
+ this.clearTableHighlight();
29610
+ this.host.render();
29611
+ return;
29612
+ }
29613
+ if (!this.host.selection.textSelection) return;
28432
29614
  this.host.clearBodySelection();
28433
29615
  this.host.render();
28434
29616
  });
@@ -28592,6 +29774,9 @@ var ListTableEventController = class {
28592
29774
  result.area === "resize-handle" ? "col-resize" : result.cursor ?? ""
28593
29775
  );
28594
29776
  const nextHover = {
29777
+ scrollbarRole: result.scrollbarRole,
29778
+ pressedScrollbarButton: this.host.hover.pressedScrollbarButton,
29779
+ pressedScrollbarPart: this.host.hover.pressedScrollbarPart,
28595
29780
  rowIndex: result.rowIndex ?? null,
28596
29781
  columnKey: result.columnKey ?? null,
28597
29782
  contentIndex: result.contentIndex,
@@ -28601,7 +29786,7 @@ var ListTableEventController = class {
28601
29786
  nestedColumnIndex: result.nestedColumnIndex,
28602
29787
  area: result.area
28603
29788
  };
28604
- const hoverChanged = this.host.hover.rowIndex !== nextHover.rowIndex || this.host.hover.columnKey !== nextHover.columnKey || this.host.hover.contentIndex !== nextHover.contentIndex || this.host.hover.nestedRowKey !== nextHover.nestedRowKey || this.host.hover.nestedRowIndex !== nextHover.nestedRowIndex || this.host.hover.nestedColumnDataIndex !== nextHover.nestedColumnDataIndex || this.host.hover.nestedColumnIndex !== nextHover.nestedColumnIndex || this.host.hover.area !== nextHover.area;
29789
+ const hoverChanged = this.host.hover.rowIndex !== nextHover.rowIndex || this.host.hover.columnKey !== nextHover.columnKey || this.host.hover.contentIndex !== nextHover.contentIndex || this.host.hover.nestedRowKey !== nextHover.nestedRowKey || this.host.hover.nestedRowIndex !== nextHover.nestedRowIndex || this.host.hover.nestedColumnDataIndex !== nextHover.nestedColumnDataIndex || this.host.hover.nestedColumnIndex !== nextHover.nestedColumnIndex || this.host.hover.area !== nextHover.area || this.host.hover.scrollbarRole !== nextHover.scrollbarRole || this.host.hover.pressedScrollbarButton !== nextHover.pressedScrollbarButton || this.host.hover.pressedScrollbarPart !== nextHover.pressedScrollbarPart;
28605
29790
  const hitChanged = didHitResultChange(
28606
29791
  this.host.debugManager.getSnapshot()?.hitTest,
28607
29792
  result
@@ -28644,7 +29829,8 @@ var ListTableEventController = class {
28644
29829
  zoom: this.host.tableZoom
28645
29830
  });
28646
29831
  const result = this.host.resolvePointerHit(position.x, position.y);
28647
- if (this.startTextSelection(result, position.x, position.y)) {
29832
+ const modifyingSelection = event.shiftKey || event.ctrlKey || event.metaKey;
29833
+ if (!modifyingSelection && this.startTextSelection(result, position.x, position.y)) {
28648
29834
  return;
28649
29835
  }
28650
29836
  if (this.host.selection.textSelection) {
@@ -28676,6 +29862,28 @@ var ListTableEventController = class {
28676
29862
  if ((result.area === "body" || result.area === "body-content") && result.columnKey === ROW_SELECTOR_COLUMN_KEY && typeof result.rowIndex === "number") {
28677
29863
  event.preventDefault();
28678
29864
  this.clearNestedTableHighlight();
29865
+ if (modifyingSelection) {
29866
+ const mode = event.ctrlKey || event.metaKey ? isRowInHighlight(this.host.rangeHighlight, result.rowIndex) ? "remove" : "add" : "extend";
29867
+ this.cellSelectionDrag = {
29868
+ kind: "row",
29869
+ startRowIndex: mode === "extend" ? this.host.rangeHighlight.selectedRowAnchorIndex ?? result.rowIndex : result.rowIndex,
29870
+ startColumnIndex: -1,
29871
+ pointerStartRowIndex: result.rowIndex,
29872
+ pointerStartColumnIndex: -1,
29873
+ mode,
29874
+ baseRangeHighlight: this.host.rangeHighlight
29875
+ };
29876
+ this.cellSelectionDragged = false;
29877
+ this.cellSelectionPointer = {
29878
+ clientX: event.clientX,
29879
+ clientY: event.clientY
29880
+ };
29881
+ this.host.canvasHost.bindWindowDragEvents(
29882
+ this.handleWindowMouseMove,
29883
+ this.handleWindowMouseUp
29884
+ );
29885
+ return;
29886
+ }
28679
29887
  this.host.selection = {
28680
29888
  rowIndex: result.rowIndex,
28681
29889
  columnKey: ROW_SELECTOR_COLUMN_KEY
@@ -28686,7 +29894,11 @@ var ListTableEventController = class {
28686
29894
  this.cellSelectionDrag = {
28687
29895
  kind: "row",
28688
29896
  startRowIndex: result.rowIndex,
28689
- startColumnIndex: -1
29897
+ startColumnIndex: -1,
29898
+ pointerStartRowIndex: result.rowIndex,
29899
+ pointerStartColumnIndex: -1,
29900
+ mode: "replace",
29901
+ baseRangeHighlight: this.host.rangeHighlight
28690
29902
  };
28691
29903
  this.cellSelectionDragged = false;
28692
29904
  this.cellSelectionPointer = {
@@ -28700,20 +29912,41 @@ var ListTableEventController = class {
28700
29912
  this.host.render(result);
28701
29913
  return;
28702
29914
  }
28703
- if (!this.host.options.rowDrag?.enabled && (result.area === "body" || result.area === "body-content") && typeof result.rowIndex === "number" && result.columnKey) {
29915
+ if ((!this.host.options.rowDrag?.enabled || modifyingSelection) && (result.area === "body" || result.area === "body-content") && typeof result.rowIndex === "number" && result.columnKey) {
28704
29916
  const columnIndex = this.host.leafColumns.findIndex(
28705
29917
  (column) => column.key === result.columnKey
28706
29918
  );
28707
29919
  if (columnIndex >= 0) {
28708
29920
  const nestedSelectionCleared = this.clearNestedTableHighlight();
28709
- this.host.rangeHighlight = {
28710
- ...this.host.rangeHighlight,
28711
- selectedCellRange: null
28712
- };
29921
+ if (!modifyingSelection) {
29922
+ this.host.rangeHighlight = {
29923
+ ...this.host.rangeHighlight,
29924
+ selectedCellRange: null,
29925
+ selectedCellRanges: null
29926
+ };
29927
+ }
29928
+ const ctrlSelection = event.ctrlKey || event.metaKey;
29929
+ const mode = ctrlSelection ? isCellInHighlight(
29930
+ this.host.rangeHighlight,
29931
+ result.rowIndex,
29932
+ columnIndex
29933
+ ) ? "remove" : "add" : event.shiftKey ? "extend" : "replace";
29934
+ const cellAnchor = this.host.rangeHighlight.selectedCellAnchor;
29935
+ const anchorColumnIndex = cellAnchor ? this.host.leafColumns.findIndex(
29936
+ (column) => column.key === cellAnchor.columnKey
29937
+ ) : -1;
29938
+ const previousColumnIndex = this.host.leafColumns.findIndex(
29939
+ (column) => column.key === this.host.selection.columnKey
29940
+ );
28713
29941
  this.cellSelectionDrag = {
28714
29942
  kind: "cell",
28715
- startRowIndex: result.rowIndex,
28716
- startColumnIndex: columnIndex
29943
+ startRowIndex: mode === "extend" ? cellAnchor?.rowIndex ?? this.host.selection.rowIndex ?? result.rowIndex : result.rowIndex,
29944
+ startColumnIndex: mode === "extend" ? anchorColumnIndex >= 0 ? anchorColumnIndex : previousColumnIndex >= 0 ? previousColumnIndex : columnIndex : columnIndex,
29945
+ pointerStartRowIndex: result.rowIndex,
29946
+ pointerStartColumnIndex: columnIndex,
29947
+ mode,
29948
+ baseRangeHighlight: this.host.rangeHighlight,
29949
+ preserveRowSelection: this.host.selection.columnKey === ROW_SELECTOR_COLUMN_KEY || this.host.rangeHighlight.selectedRowRanges != null
28717
29950
  };
28718
29951
  this.cellSelectionDragged = false;
28719
29952
  this.cellSelectionPointer = {
@@ -28727,6 +29960,7 @@ var ListTableEventController = class {
28727
29960
  if (nestedSelectionCleared) {
28728
29961
  this.host.render(result);
28729
29962
  }
29963
+ if (modifyingSelection) return;
28730
29964
  }
28731
29965
  }
28732
29966
  if (result.area === "resize-handle" && result.columnKey) {
@@ -28817,11 +30051,39 @@ var ListTableEventController = class {
28817
30051
  result.scrollbarRole === "thumb" ? "grabbing" : "pointer"
28818
30052
  );
28819
30053
  if (result.scrollbarRole === "decrease-button") {
30054
+ if (this.scrollbarButtonFeedbackTimer != null) {
30055
+ window.clearTimeout(this.scrollbarButtonFeedbackTimer);
30056
+ this.scrollbarButtonFeedbackTimer = null;
30057
+ }
30058
+ this.host.hover = {
30059
+ ...this.host.hover,
30060
+ area: result.area,
30061
+ scrollbarRole: result.scrollbarRole,
30062
+ pressedScrollbarButton: {
30063
+ axis: result.area === "horizontal-scrollbar" ? "horizontal" : "vertical",
30064
+ role: result.scrollbarRole
30065
+ }
30066
+ };
30067
+ this.host.scheduleRender();
28820
30068
  this.stepScrollbar(result.area, -1, viewport);
28821
30069
  this.startContinuousScroll(result.area, -1, viewport);
28822
30070
  return;
28823
30071
  }
28824
30072
  if (result.scrollbarRole === "increase-button") {
30073
+ if (this.scrollbarButtonFeedbackTimer != null) {
30074
+ window.clearTimeout(this.scrollbarButtonFeedbackTimer);
30075
+ this.scrollbarButtonFeedbackTimer = null;
30076
+ }
30077
+ this.host.hover = {
30078
+ ...this.host.hover,
30079
+ area: result.area,
30080
+ scrollbarRole: result.scrollbarRole,
30081
+ pressedScrollbarButton: {
30082
+ axis: result.area === "horizontal-scrollbar" ? "horizontal" : "vertical",
30083
+ role: result.scrollbarRole
30084
+ }
30085
+ };
30086
+ this.host.scheduleRender();
28825
30087
  this.stepScrollbar(result.area, 1, viewport);
28826
30088
  this.startContinuousScroll(result.area, 1, viewport);
28827
30089
  return;
@@ -28833,9 +30095,15 @@ var ListTableEventController = class {
28833
30095
  }
28834
30096
  const { thumb, track } = horizontalScrollbar;
28835
30097
  if (result.scrollbarRole === "track") {
30098
+ this.flashScrollbarPart("horizontal", "track");
28836
30099
  this.jumpScrollbar("horizontal", position.x, track, thumb, viewport);
28837
30100
  return;
28838
30101
  }
30102
+ this.host.hover = {
30103
+ ...this.host.hover,
30104
+ pressedScrollbarPart: { axis: "horizontal", role: "thumb" }
30105
+ };
30106
+ this.host.scheduleRender();
28839
30107
  this.host.draggingScrollbar = {
28840
30108
  axis: "horizontal",
28841
30109
  pointerOffset: position.x - thumb.x,
@@ -28851,9 +30119,15 @@ var ListTableEventController = class {
28851
30119
  }
28852
30120
  const { thumb, track } = verticalScrollbar;
28853
30121
  if (result.scrollbarRole === "track") {
30122
+ this.flashScrollbarPart("vertical", "track");
28854
30123
  this.jumpScrollbar("vertical", position.y, track, thumb, viewport);
28855
30124
  return;
28856
30125
  }
30126
+ this.host.hover = {
30127
+ ...this.host.hover,
30128
+ pressedScrollbarPart: { axis: "vertical", role: "thumb" }
30129
+ };
30130
+ this.host.scheduleRender();
28857
30131
  this.host.draggingScrollbar = {
28858
30132
  axis: "vertical",
28859
30133
  pointerOffset: position.y - thumb.y,
@@ -28966,15 +30240,47 @@ var ListTableEventController = class {
28966
30240
  getRows: () => this.host.getDisplayData(),
28967
30241
  getAllRows: () => this.host.options.dataSource,
28968
30242
  getExportSummaryEnabled: () => Boolean(this.host.currentRenderSnapshot?.hasSummary),
30243
+ getExportSortState: () => this.host.getSortState(),
30244
+ getExportColumns: () => getListTableExportCandidateColumns(this.host.options.columns),
28969
30245
  onCopyImage: (scope) => this.copyImage(scope, event),
30246
+ scrollbarColumnCount: this.host.leafColumns.filter(
30247
+ (column) => !isSystemColumnKey(column.key)
30248
+ ).length,
30249
+ onScrollToPosition: (row, column) => {
30250
+ const columns = this.host.leafColumns.filter(
30251
+ (item) => !isSystemColumnKey(item.key)
30252
+ );
30253
+ const targetColumn = column == null ? null : columns[column - 1];
30254
+ const colIndex = targetColumn ? this.host.leafColumns.findIndex(
30255
+ (item) => item.key === targetColumn.key
30256
+ ) : void 0;
30257
+ this.host.scrollTo({
30258
+ rowIndex: row == null ? void 0 : row - 1,
30259
+ colIndex,
30260
+ behavior: "smooth"
30261
+ });
30262
+ },
30263
+ onChangeScrollbar: (value) => {
30264
+ this.host.options.scrollbar = value;
30265
+ this.host.options.ui?.onScrollbarChange?.(value);
30266
+ this.host.persistColumnConfig();
30267
+ this.host.render();
30268
+ },
30269
+ onResetScrollbar: () => {
30270
+ this.host.options.scrollbar = void 0;
30271
+ this.host.persistColumnConfig();
30272
+ this.host.render();
30273
+ },
28970
30274
  onCreateChart: () => createListTableChartData({
28971
30275
  rows: this.host.getDisplayData(),
28972
30276
  columns: this.host.leafColumns,
28973
30277
  columnKey: contextResult.columnKey ?? "",
28974
- rowIndex: typeof contextResult.rowIndex === "number" ? contextResult.rowIndex : null,
30278
+ rowIndex: this.host.selection.rowIndex ?? (typeof contextResult.rowIndex === "number" ? contextResult.rowIndex : null),
28975
30279
  selectionRange: this.host.rangeHighlight.selectedCellRange,
28976
30280
  selectedRowRange: this.host.rangeHighlight.selectedRowRange,
28977
- selectedColumnRange: this.host.rangeHighlight.selectedColumnRange
30281
+ selectedColumnRange: this.host.rangeHighlight.selectedColumnRange,
30282
+ selectedColumnKeys: this.host.rangeHighlight.selectedColumnKeys,
30283
+ getRowKey: this.host.options.rowKey != null ? (record, index) => getRowKey(this.host.options, record, index) : void 0
28978
30284
  }),
28979
30285
  onExportImage: (scope) => this.copyImage(scope, event, true),
28980
30286
  canCopySelectionImage: resolveImageSelection(this.host) != null,
@@ -28998,8 +30304,8 @@ var ListTableEventController = class {
28998
30304
  getColumns: () => this.host.leafColumns,
28999
30305
  getHeaderTree: () => this.host.headerTree,
29000
30306
  getFrozenRowPosition: (rowIndex) => this.host.getFrozenRowPosition(rowIndex),
29001
- startExportTask: (task, text, defaultFileName) => {
29002
- this.host.startExportTask(task, text, defaultFileName);
30307
+ startExportTask: (task, text, defaultFileName, dialog) => {
30308
+ this.host.startExportTask(task, text, defaultFileName, dialog);
29003
30309
  },
29004
30310
  contentDownload: this.host.resolveContentDownloadAction(hitContent),
29005
30311
  onSelectHeader: (columnKey, rect) => {
@@ -29008,18 +30314,22 @@ var ListTableEventController = class {
29008
30314
  this.host.selectHeader(columnKey, rect);
29009
30315
  },
29010
30316
  onSelectBodyRow: (rowIndex, columnKey) => {
29011
- const selectedCellRange = this.host.rangeHighlight.selectedCellRange;
29012
30317
  const columnIndex = this.host.leafColumns.findIndex(
29013
30318
  (column) => column.key === columnKey
29014
30319
  );
30320
+ const isSelectedCell = columnIndex >= 0 && isCellInHighlight(this.host.rangeHighlight, rowIndex, columnIndex);
29015
30321
  this.host.selection = {
29016
30322
  rowIndex,
29017
30323
  columnKey
29018
30324
  };
29019
30325
  this.host.clearSelectedHeader();
29020
- if (!selectedCellRange || rowIndex < selectedCellRange.startRowIndex || rowIndex > selectedCellRange.endRowIndex || columnIndex < selectedCellRange.startColumnIndex || columnIndex > selectedCellRange.endColumnIndex) {
30326
+ if (!isSelectedCell && !isRowInHighlight(this.host.rangeHighlight, rowIndex)) {
29021
30327
  this.host.rangeHighlight = resolveNextRowHighlightForContextMenu({
29022
- current: this.host.rangeHighlight,
30328
+ current: {
30329
+ ...this.host.rangeHighlight,
30330
+ selectedCellRange: null,
30331
+ selectedCellRanges: null
30332
+ },
29023
30333
  rowIndex
29024
30334
  });
29025
30335
  }
@@ -29315,6 +30625,14 @@ var ListTableEventController = class {
29315
30625
  const result = event.shiftKey && rawResult.area === "column-collapse-trigger" ? this.host.resolvePointerHit(position.x, position.y, {
29316
30626
  excludeKinds: ["column-collapse-trigger"]
29317
30627
  }) : rawResult;
30628
+ const toggleColumn = event.ctrlKey || event.metaKey;
30629
+ const preserveAnimatedSortSelection = result.area === "sort-trigger" && this.host.leafColumns.some(
30630
+ (column) => column.key === result.columnKey && typeof column.sorter === "object" && column.sorter.animation === true
30631
+ );
30632
+ const previousCell = {
30633
+ rowIndex: this.host.selection.rowIndex,
30634
+ columnKey: this.host.selection.columnKey
30635
+ };
29318
30636
  if (result.area === "grouping-remove" && result.columnKey) {
29319
30637
  this.host.removeGroupingColumn?.(result.columnKey);
29320
30638
  this.host.suppressNextClick = true;
@@ -29337,6 +30655,11 @@ var ListTableEventController = class {
29337
30655
  this.host.suppressNextClick = false;
29338
30656
  return;
29339
30657
  }
30658
+ if (result.area === "empty" && this.host.options.clearSelectionOnClick?.blankCanvas) {
30659
+ this.clearTableHighlight();
30660
+ this.host.render(result);
30661
+ return;
30662
+ }
29340
30663
  const isNestedTableHit = result.contentKey === "nested-table";
29341
30664
  if (isNestedTableHit) {
29342
30665
  this.clearParentTableHighlight();
@@ -29368,6 +30691,7 @@ var ListTableEventController = class {
29368
30691
  selectedRowRange: rowCount > 0 ? { start: 0, end: rowCount - 1 } : null,
29369
30692
  selectedColumnAnchorKey: this.host.leafColumns[0]?.key ?? null,
29370
30693
  selectedColumnRange: columnRangeEnd >= 0 ? { start: 0, end: columnRangeEnd } : null,
30694
+ selectedColumnKeys: null,
29371
30695
  selectedCellRange: rowCount > 0 && columnCount > 0 ? {
29372
30696
  startRowIndex: 0,
29373
30697
  endRowIndex: rowCount - 1,
@@ -29392,6 +30716,7 @@ var ListTableEventController = class {
29392
30716
  selectedRowRange: rowCount > 0 ? { start: 0, end: rowCount - 1 } : null,
29393
30717
  selectedColumnAnchorKey: this.host.leafColumns[0]?.key ?? null,
29394
30718
  selectedColumnRange: columnCount > 0 ? { start: 0, end: columnCount - 1 } : null,
30719
+ selectedColumnKeys: null,
29395
30720
  selectedCellRange: rowCount > 0 && columnCount > 0 ? {
29396
30721
  startRowIndex: 0,
29397
30722
  endRowIndex: rowCount - 1,
@@ -29412,7 +30737,48 @@ var ListTableEventController = class {
29412
30737
  if ((result.area === "body" || result.area === "body-content") && result.columnKey === ROW_SELECTOR_COLUMN_KEY && typeof result.rowIndex === "number") {
29413
30738
  this.host.clearSelectedHeader();
29414
30739
  this.host.summarySelected = false;
29415
- this.selectRowRange(result.rowIndex, result.rowIndex);
30740
+ this.host.rangeHighlight = resolveRowHighlightForSelectorClick({
30741
+ current: this.host.rangeHighlight,
30742
+ rowIndex: result.rowIndex,
30743
+ shiftKey: event.shiftKey,
30744
+ ctrlKey: toggleColumn
30745
+ });
30746
+ if (!isRowInHighlight(this.host.rangeHighlight, result.rowIndex)) {
30747
+ const hasSelectedRows = this.host.rangeHighlight.selectedRowRanges?.length || this.host.rangeHighlight.selectedRowRange;
30748
+ this.host.selection = {
30749
+ rowIndex: null,
30750
+ columnKey: hasSelectedRows ? ROW_SELECTOR_COLUMN_KEY : null
30751
+ };
30752
+ }
30753
+ this.host.render(result);
30754
+ this.host.updateTooltip(result);
30755
+ return;
30756
+ }
30757
+ if ((event.shiftKey || toggleColumn) && (result.area === "body" || result.area === "body-content") && typeof result.rowIndex === "number" && result.columnKey && !isSystemColumnKey(result.columnKey)) {
30758
+ const columnIndex = this.host.leafColumns.findIndex(
30759
+ (column) => column.key === result.columnKey
30760
+ );
30761
+ this.host.clearSelectedHeader();
30762
+ this.host.rangeHighlight = resolveCellHighlightForClick({
30763
+ current: this.host.rangeHighlight,
30764
+ rowIndex: result.rowIndex,
30765
+ columnKey: result.columnKey,
30766
+ leafColumnKeys: this.host.leafColumns.map((column) => column.key),
30767
+ previousCell: previousCell.rowIndex != null && previousCell.columnKey ? {
30768
+ rowIndex: previousCell.rowIndex,
30769
+ columnKey: previousCell.columnKey
30770
+ } : null,
30771
+ preserveRowSelection: previousCell.columnKey === ROW_SELECTOR_COLUMN_KEY || this.host.rangeHighlight.selectedRowRanges != null,
30772
+ shiftKey: event.shiftKey,
30773
+ ctrlKey: toggleColumn
30774
+ });
30775
+ if (columnIndex >= 0 && !isCellInHighlight(
30776
+ this.host.rangeHighlight,
30777
+ result.rowIndex,
30778
+ columnIndex
30779
+ )) {
30780
+ this.host.selection = { rowIndex: null, columnKey: null };
30781
+ }
29416
30782
  this.host.render(result);
29417
30783
  this.host.updateTooltip(result);
29418
30784
  return;
@@ -29424,13 +30790,20 @@ var ListTableEventController = class {
29424
30790
  }
29425
30791
  }
29426
30792
  this.host.summarySelected = result.area === "summary";
29427
- if ((result.area === "header" || result.area === "header-selection" || result.area === "sort-trigger" || result.area === "filter-trigger" || result.area === "fixed-trigger" || event.shiftKey && result.area === "column-collapse-trigger") && result.columnKey) {
30793
+ if ((result.area === "header" || result.area === "header-selection" || result.area === "sort-trigger" && !preserveAnimatedSortSelection || result.area === "filter-trigger" || result.area === "fixed-trigger" || event.shiftKey && result.area === "column-collapse-trigger") && result.columnKey) {
29428
30794
  this.host.clearBodySelection();
29429
- this.host.resetRangeHighlightForHeaderSelection(event.shiftKey);
29430
- this.host.selectHeader(
29431
- result.columnKey,
29432
- result.area === "header" ? result.rect : null
30795
+ this.host.resetRangeHighlightForHeaderSelection(
30796
+ event.shiftKey,
30797
+ toggleColumn
29433
30798
  );
30799
+ if (toggleColumn) {
30800
+ this.host.clearSelectedHeader();
30801
+ } else {
30802
+ this.host.selectHeader(
30803
+ result.columnKey,
30804
+ result.area === "header" ? result.rect : null
30805
+ );
30806
+ }
29434
30807
  }
29435
30808
  if (result.area === "summary") {
29436
30809
  if (!result.columnKey) {
@@ -29448,7 +30821,7 @@ var ListTableEventController = class {
29448
30821
  this.host.updateTooltip(result);
29449
30822
  return;
29450
30823
  }
29451
- const isHeaderRangeGesture = event.shiftKey && result.columnKey && (result.area === "header" || result.area === "sort-trigger" || result.area === "filter-trigger" || result.area === "fixed-trigger" || result.area === "column-collapse-trigger");
30824
+ const isHeaderRangeGesture = (event.shiftKey || toggleColumn) && result.columnKey && (result.area === "header" || result.area === "sort-trigger" && !preserveAnimatedSortSelection || result.area === "filter-trigger" || result.area === "fixed-trigger" || result.area === "column-collapse-trigger");
29452
30825
  if ((result.area === "body" || result.area === "body-content") && typeof result.rowIndex === "number" && result.columnKey) {
29453
30826
  this.host.clearSelectedHeader();
29454
30827
  this.host.updateRangeHighlightForBodyInteraction({
@@ -29457,15 +30830,26 @@ var ListTableEventController = class {
29457
30830
  shiftKey: event.shiftKey,
29458
30831
  rowSpan: result.rowSpan
29459
30832
  });
30833
+ if (!isSystemColumnKey(result.columnKey)) {
30834
+ this.host.rangeHighlight = resolveCellHighlightForClick({
30835
+ current: this.host.rangeHighlight,
30836
+ rowIndex: result.rowIndex,
30837
+ columnKey: result.columnKey,
30838
+ leafColumnKeys: this.host.leafColumns.map((column) => column.key),
30839
+ shiftKey: false,
30840
+ ctrlKey: false
30841
+ });
30842
+ }
29460
30843
  }
29461
- if ((result.area === "header" || result.area === "sort-trigger" || result.area === "filter-trigger" || result.area === "fixed-trigger" || isHeaderRangeGesture) && result.columnKey) {
30844
+ if ((result.area === "header" || result.area === "sort-trigger" && !preserveAnimatedSortSelection || result.area === "filter-trigger" || result.area === "fixed-trigger" || isHeaderRangeGesture) && result.columnKey) {
29462
30845
  this.host.rangeHighlight = {
29463
30846
  ...this.host.rangeHighlight,
29464
30847
  selectedCellRange: null
29465
30848
  };
29466
30849
  this.host.updateRangeHighlightForHeaderClick(
29467
30850
  result.columnKey,
29468
- event.shiftKey
30851
+ event.shiftKey,
30852
+ toggleColumn
29469
30853
  );
29470
30854
  }
29471
30855
  if (isHeaderRangeGesture) {
@@ -29801,12 +31185,24 @@ var ListTableEventController = class {
29801
31185
  } else if (!activated && this.host.draggingReorder.columnKey) {
29802
31186
  const columnKey = this.host.draggingReorder.columnKey;
29803
31187
  this.host.clearBodySelection();
29804
- this.host.resetRangeHighlightForHeaderSelection(event.shiftKey);
29805
- this.host.selectHeader(
31188
+ const toggleColumn = event.ctrlKey || event.metaKey;
31189
+ this.host.resetRangeHighlightForHeaderSelection(
31190
+ event.shiftKey,
31191
+ toggleColumn
31192
+ );
31193
+ if (toggleColumn) {
31194
+ this.host.clearSelectedHeader();
31195
+ } else {
31196
+ this.host.selectHeader(
31197
+ columnKey,
31198
+ this.host.draggingReorder.selectedHeaderRect
31199
+ );
31200
+ }
31201
+ this.host.updateRangeHighlightForHeaderClick(
29806
31202
  columnKey,
29807
- this.host.draggingReorder.selectedHeaderRect
31203
+ event.shiftKey,
31204
+ toggleColumn
29808
31205
  );
29809
- this.host.updateRangeHighlightForHeaderClick(columnKey, event.shiftKey);
29810
31206
  this.host.suppressNextClick = true;
29811
31207
  this.host.render();
29812
31208
  }
@@ -30033,6 +31429,14 @@ var ListTableEventController = class {
30033
31429
  this.host.render();
30034
31430
  }
30035
31431
  destroy() {
31432
+ if (this.scrollbarButtonFeedbackTimer != null) {
31433
+ window.clearTimeout(this.scrollbarButtonFeedbackTimer);
31434
+ this.scrollbarButtonFeedbackTimer = null;
31435
+ }
31436
+ if (this.scrollbarPartFeedbackTimer != null) {
31437
+ window.clearTimeout(this.scrollbarPartFeedbackTimer);
31438
+ this.scrollbarPartFeedbackTimer = null;
31439
+ }
30036
31440
  this.cancelPendingEditableCellRowSelection();
30037
31441
  this.stopContinuousScroll();
30038
31442
  this.stopTextSelectionAutoScroll();
@@ -30162,10 +31566,11 @@ var ListTableEventController = class {
30162
31566
  getRows: () => resolveNestedTableDisplayRows(content, getNestedState()),
30163
31567
  getAllRows: () => content.dataSource,
30164
31568
  getExportSummaryEnabled: () => getNestedState()?.summaryVisible === true,
31569
+ getExportSortState: () => getNestedState()?.sortState ?? [],
30165
31570
  getColumns: () => columns,
30166
31571
  getHeaderTree: () => headerTree,
30167
31572
  hideMenu,
30168
- startExportTask: (task, text, defaultFileName) => this.host.startExportTask(task, text, defaultFileName),
31573
+ startExportTask: (task, text, defaultFileName, dialog) => this.host.startExportTask(task, text, defaultFileName, dialog),
30169
31574
  onFreezeRow: () => {
30170
31575
  },
30171
31576
  onUnfreezeRow: () => {
@@ -30636,6 +32041,11 @@ var ListTableEventController = class {
30636
32041
  searchMatch: this.host.rangeHighlight.searchMatch
30637
32042
  };
30638
32043
  }
32044
+ /** 清除可视选区,但保留查找结果与业务行选择数据。 */
32045
+ clearTableHighlight() {
32046
+ this.clearParentTableHighlight();
32047
+ this.clearNestedTableHighlight();
32048
+ }
30639
32049
  /** 父表格进入选区交互时清理全部子表格选区。 */
30640
32050
  clearNestedTableHighlight() {
30641
32051
  this.activeNestedTableHit = null;
@@ -30643,9 +32053,31 @@ var ListTableEventController = class {
30643
32053
  }
30644
32054
  startContinuousScroll(area, direction, viewport) {
30645
32055
  this.stopContinuousScroll();
32056
+ const axis = area === "horizontal-scrollbar" ? "horizontal" : "vertical";
32057
+ const style = resolveCanvasScrollbarAxis(this.host.options.scrollbar, axis);
32058
+ const startedAt = Date.now();
32059
+ let previousAt = startedAt;
30646
32060
  this.continuousScrollTimer = window.setInterval(() => {
30647
- this.stepScrollbar(area, direction, viewport);
30648
- }, 80);
32061
+ const now2 = Date.now();
32062
+ const elapsed = Math.max(now2 - previousAt, 0);
32063
+ previousAt = now2;
32064
+ const distance = resolveCanvasScrollbarHoldSpeed(
32065
+ now2 - startedAt,
32066
+ style.maxScrollSpeed
32067
+ ) * elapsed * direction / 1e3;
32068
+ const base = this.host.animationController.getWheelScrollTarget() ?? this.host.scroll;
32069
+ const next = {
32070
+ ...base,
32071
+ left: axis === "horizontal" ? Math.min(
32072
+ Math.max(base.left + distance, 0),
32073
+ viewport.maxScrollLeft
32074
+ ) : base.left,
32075
+ top: axis === "vertical" ? Math.min(Math.max(base.top + distance, 0), viewport.maxScrollTop) : base.top
32076
+ };
32077
+ if (next.left !== base.left || next.top !== base.top) {
32078
+ this.host.animationController.startWheelScrollSmoothing(next);
32079
+ }
32080
+ }, 32);
30649
32081
  this.host.canvasHost.bindWindowDragEvents(
30650
32082
  this.handleWindowMouseMove,
30651
32083
  this.handleWindowMouseUp
@@ -30658,22 +32090,19 @@ var ListTableEventController = class {
30658
32090
  }
30659
32091
  }
30660
32092
  stepScrollbar(area, direction, viewport) {
32093
+ const base = this.host.animationController.getWheelScrollTarget() ?? this.host.scroll;
30661
32094
  const nextScroll = stepScrollbarScroll({
30662
- current: this.host.scroll,
32095
+ current: base,
30663
32096
  area,
30664
32097
  direction,
30665
32098
  viewport,
30666
32099
  rowHeight: this.host.currentRenderSnapshot?.rowHeight ?? DEFAULT_ROW_HEIGHT,
30667
32100
  horizontalStep: HORIZONTAL_SCROLL_STEP
30668
32101
  });
30669
- if (!this.host.applyUserScroll(nextScroll)) {
32102
+ if (nextScroll.left === base.left && nextScroll.top === base.top) {
30670
32103
  return;
30671
32104
  }
30672
- this.host.markScrollbarActive();
30673
- this.host.scheduleRender();
30674
- if (area === "vertical-scrollbar") {
30675
- this.host.maybeLoadNextScrollPage();
30676
- }
32105
+ this.host.animationController.startWheelScrollSmoothing(nextScroll);
30677
32106
  }
30678
32107
  jumpScrollbar(axis, pointerValue, track, thumb, viewport) {
30679
32108
  const nextScroll = jumpScrollbarScroll({
@@ -30694,6 +32123,22 @@ var ListTableEventController = class {
30694
32123
  }
30695
32124
  }
30696
32125
  finishWindowDragCleanup(options) {
32126
+ if (this.host.hover.pressedScrollbarButton) {
32127
+ this.scrollbarButtonFeedbackTimer = window.setTimeout(() => {
32128
+ this.scrollbarButtonFeedbackTimer = null;
32129
+ this.host.hover = {
32130
+ ...this.host.hover,
32131
+ pressedScrollbarButton: void 0
32132
+ };
32133
+ this.host.scheduleRender();
32134
+ }, 140);
32135
+ }
32136
+ if (this.host.hover.pressedScrollbarPart?.role === "thumb") {
32137
+ this.host.hover = {
32138
+ ...this.host.hover,
32139
+ pressedScrollbarPart: void 0
32140
+ };
32141
+ }
30697
32142
  this.host.draggingScrollbar = null;
30698
32143
  this.host.draggingResize = null;
30699
32144
  this.host.draggingReorder = null;
@@ -30707,6 +32152,24 @@ var ListTableEventController = class {
30707
32152
  this.host.markScrollbarActive();
30708
32153
  this.host.render();
30709
32154
  }
32155
+ flashScrollbarPart(axis, role) {
32156
+ if (this.scrollbarPartFeedbackTimer != null) {
32157
+ window.clearTimeout(this.scrollbarPartFeedbackTimer);
32158
+ }
32159
+ this.host.hover = {
32160
+ ...this.host.hover,
32161
+ pressedScrollbarPart: { axis, role }
32162
+ };
32163
+ this.host.scheduleRender();
32164
+ this.scrollbarPartFeedbackTimer = window.setTimeout(() => {
32165
+ this.scrollbarPartFeedbackTimer = null;
32166
+ this.host.hover = {
32167
+ ...this.host.hover,
32168
+ pressedScrollbarPart: void 0
32169
+ };
32170
+ this.host.scheduleRender();
32171
+ }, 140);
32172
+ }
30710
32173
  startTextSelection(result, pointerX, pointerY) {
30711
32174
  if (result.area !== "body-content" && result.area !== "header" && result.area !== "summary" || !result.columnKey || !result.textSelectionText || !result.textSelectionFont || !result.textSelectionFragmentKey || !result.rect) {
30712
32175
  return false;
@@ -31054,16 +32517,46 @@ var ListTableEventController = class {
31054
32517
  return false;
31055
32518
  }
31056
32519
  if (drag.kind === "row") {
32520
+ if (drag.mode !== "replace" && !this.cellSelectionDragged && result.rowIndex === drag.pointerStartRowIndex || drag.lastRowIndex === result.rowIndex) {
32521
+ return false;
32522
+ }
31057
32523
  const nextRange2 = {
31058
32524
  start: Math.min(drag.startRowIndex, result.rowIndex),
31059
32525
  end: Math.max(drag.startRowIndex, result.rowIndex)
31060
32526
  };
31061
32527
  const currentRange2 = this.host.rangeHighlight.selectedRowRange;
31062
- if (currentRange2?.start === nextRange2.start && currentRange2.end === nextRange2.end) {
32528
+ if (drag.mode === "replace" && currentRange2?.start === nextRange2.start && currentRange2.end === nextRange2.end) {
31063
32529
  return false;
31064
32530
  }
31065
- this.cellSelectionDragged = this.cellSelectionDragged || result.rowIndex !== drag.startRowIndex;
31066
- this.selectRowRange(drag.startRowIndex, result.rowIndex);
32531
+ this.cellSelectionDragged = this.cellSelectionDragged || result.rowIndex !== drag.pointerStartRowIndex;
32532
+ drag.lastRowIndex = result.rowIndex;
32533
+ if (drag.mode === "replace") {
32534
+ this.selectRowRange(drag.startRowIndex, result.rowIndex);
32535
+ } else if (drag.mode === "extend") {
32536
+ this.host.rangeHighlight = resolveRowHighlightForSelectorClick({
32537
+ current: {
32538
+ ...drag.baseRangeHighlight,
32539
+ selectedRowAnchorIndex: drag.startRowIndex
32540
+ },
32541
+ rowIndex: result.rowIndex,
32542
+ shiftKey: true,
32543
+ ctrlKey: false
32544
+ });
32545
+ } else {
32546
+ this.host.rangeHighlight = resolveRowHighlightForDrag({
32547
+ current: drag.baseRangeHighlight,
32548
+ startRowIndex: drag.startRowIndex,
32549
+ endRowIndex: result.rowIndex,
32550
+ remove: drag.mode === "remove"
32551
+ });
32552
+ }
32553
+ if (drag.mode !== "replace") {
32554
+ this.host.clearSelectedHeader();
32555
+ this.host.selection = {
32556
+ rowIndex: drag.mode === "remove" ? null : result.rowIndex,
32557
+ columnKey: ROW_SELECTOR_COLUMN_KEY
32558
+ };
32559
+ }
31067
32560
  if (options?.scheduleRender !== false) {
31068
32561
  this.host.scheduleRender(result);
31069
32562
  }
@@ -31075,7 +32568,7 @@ var ListTableEventController = class {
31075
32568
  if (columnIndex < 0) {
31076
32569
  return false;
31077
32570
  }
31078
- if (result.rowIndex === drag.startRowIndex && columnIndex === drag.startColumnIndex) {
32571
+ if (!this.cellSelectionDragged && result.rowIndex === drag.pointerStartRowIndex && columnIndex === drag.pointerStartColumnIndex || drag.lastRowIndex === result.rowIndex && drag.lastColumnIndex === columnIndex) {
31079
32572
  return false;
31080
32573
  }
31081
32574
  const nextRange = {
@@ -31085,14 +32578,53 @@ var ListTableEventController = class {
31085
32578
  endColumnIndex: Math.max(drag.startColumnIndex, columnIndex)
31086
32579
  };
31087
32580
  const currentRange = this.host.rangeHighlight.selectedCellRange;
31088
- if (currentRange?.startRowIndex === nextRange.startRowIndex && currentRange.endRowIndex === nextRange.endRowIndex && currentRange.startColumnIndex === nextRange.startColumnIndex && currentRange.endColumnIndex === nextRange.endColumnIndex) {
32581
+ if (drag.mode === "replace" && currentRange?.startRowIndex === nextRange.startRowIndex && currentRange.endRowIndex === nextRange.endRowIndex && currentRange.startColumnIndex === nextRange.startColumnIndex && currentRange.endColumnIndex === nextRange.endColumnIndex) {
31089
32582
  return false;
31090
32583
  }
31091
32584
  this.cellSelectionDragged = true;
31092
- this.host.rangeHighlight = {
31093
- ...this.host.rangeHighlight,
31094
- selectedCellRange: nextRange
31095
- };
32585
+ drag.lastRowIndex = result.rowIndex;
32586
+ drag.lastColumnIndex = columnIndex;
32587
+ if (drag.mode === "replace") {
32588
+ this.host.rangeHighlight = {
32589
+ ...this.host.rangeHighlight,
32590
+ selectedCellRange: nextRange,
32591
+ selectedCellRanges: null,
32592
+ selectedCellAnchor: {
32593
+ rowIndex: drag.startRowIndex,
32594
+ columnKey: this.host.leafColumns[drag.startColumnIndex]?.key ?? result.columnKey
32595
+ }
32596
+ };
32597
+ } else if (drag.mode === "extend") {
32598
+ this.host.rangeHighlight = resolveCellHighlightForClick({
32599
+ current: {
32600
+ ...drag.baseRangeHighlight,
32601
+ selectedCellAnchor: {
32602
+ rowIndex: drag.startRowIndex,
32603
+ columnKey: this.host.leafColumns[drag.startColumnIndex]?.key ?? result.columnKey
32604
+ }
32605
+ },
32606
+ rowIndex: result.rowIndex,
32607
+ columnKey: result.columnKey,
32608
+ leafColumnKeys: this.host.leafColumns.map((column) => column.key),
32609
+ shiftKey: true,
32610
+ ctrlKey: false
32611
+ });
32612
+ } else {
32613
+ this.host.rangeHighlight = resolveCellHighlightForDrag({
32614
+ current: drag.baseRangeHighlight,
32615
+ startRowIndex: drag.startRowIndex,
32616
+ endRowIndex: result.rowIndex,
32617
+ startColumnIndex: drag.startColumnIndex,
32618
+ endColumnIndex: columnIndex,
32619
+ columnKey: this.host.leafColumns[drag.startColumnIndex]?.key ?? result.columnKey,
32620
+ remove: drag.mode === "remove",
32621
+ preserveRowSelection: drag.preserveRowSelection === true
32622
+ });
32623
+ }
32624
+ if (drag.mode !== "replace") {
32625
+ this.host.clearSelectedHeader();
32626
+ this.host.selection = drag.mode === "remove" ? { rowIndex: null, columnKey: null } : { rowIndex: result.rowIndex, columnKey: result.columnKey };
32627
+ }
31096
32628
  if (options?.scheduleRender !== false) {
31097
32629
  this.host.scheduleRender(result);
31098
32630
  }
@@ -31176,9 +32708,13 @@ var ListTableEventController = class {
31176
32708
  start: Math.min(startRowIndex, endRowIndex),
31177
32709
  end: Math.max(startRowIndex, endRowIndex)
31178
32710
  },
32711
+ selectedRowRanges: null,
31179
32712
  selectedColumnAnchorKey: null,
31180
32713
  selectedColumnRange: null,
31181
- selectedCellRange: null
32714
+ selectedColumnKeys: null,
32715
+ selectedCellRange: null,
32716
+ selectedCellRanges: null,
32717
+ selectedCellAnchor: null
31182
32718
  };
31183
32719
  }
31184
32720
  };
@@ -31497,6 +33033,7 @@ function createListTableEventHost(core) {
31497
33033
  // 可见行在百万行窗口化后只包含当前视口;事件层需要完整的查询结果,
31498
33034
  // 否则自动列宽等基于全局 dataRowIndex 的逻辑会在深滚动时丢失采样行。
31499
33035
  getDisplayData: () => core.queryController.getDisplayData(),
33036
+ getSortState: () => core.storeFacade.sortState,
31500
33037
  getSummaryValueMap: () => core.summaryController.getSummaryValueMap(),
31501
33038
  getSummaryValuesAsync: (snapshot) => core.summaryController.getSummaryValuesAsync(snapshot),
31502
33039
  scrollTo: (options) => core.scrollTo(options),
@@ -31514,11 +33051,12 @@ function createListTableEventHost(core) {
31514
33051
  clearBodySelection: () => core.selectionController.clearBodySelection(),
31515
33052
  clearSelectedHeader: () => core.selectionController.clearSelectedHeader(),
31516
33053
  selectHeader: (columnKey, rect) => core.selectionController.selectHeader(columnKey, rect),
31517
- resetRangeHighlightForHeaderSelection: (shiftKey) => core.selectionController.resetRangeHighlightForHeaderSelection(shiftKey),
33054
+ resetRangeHighlightForHeaderSelection: (shiftKey, ctrlKey) => core.selectionController.resetRangeHighlightForHeaderSelection(shiftKey, ctrlKey),
31518
33055
  updateRangeHighlightForBodyInteraction: (params) => core.selectionController.updateRangeHighlightForBodyInteraction(params),
31519
- updateRangeHighlightForHeaderClick: (columnKey, shiftKey) => core.selectionController.updateRangeHighlightForHeaderClick(
33056
+ updateRangeHighlightForHeaderClick: (columnKey, shiftKey, ctrlKey) => core.selectionController.updateRangeHighlightForHeaderClick(
31520
33057
  columnKey,
31521
- shiftKey
33058
+ shiftKey,
33059
+ ctrlKey
31522
33060
  ),
31523
33061
  updateRangeHighlightForHeaderContextMenu: (columnKey) => core.selectionController.updateRangeHighlightForHeaderContextMenu(
31524
33062
  columnKey
@@ -31561,7 +33099,7 @@ function createListTableEventHost(core) {
31561
33099
  return snapshot?.columnSegments ?? core.columnSegments;
31562
33100
  },
31563
33101
  persistColumnConfig: () => core.persistenceController.persistColumnConfig(),
31564
- startExportTask: (task, text, defaultFileName) => {
33102
+ startExportTask: (task, text, defaultFileName, dialog) => {
31565
33103
  const configured = core.options.exportOptions?.fileName?.trim();
31566
33104
  const extension = defaultFileName?.match(/\.(xlsx|csv|txt|json)$/i)?.[0];
31567
33105
  const fileName = configured && extension ? configured.replace(/\.(xlsx|csv|txt|json)$/i, "") + extension : defaultFileName;
@@ -31569,7 +33107,9 @@ function createListTableEventHost(core) {
31569
33107
  task,
31570
33108
  text,
31571
33109
  void 0,
31572
- fileName
33110
+ fileName,
33111
+ void 0,
33112
+ dialog
31573
33113
  );
31574
33114
  },
31575
33115
  resolveContentDownloadAction: (content) => core.contentActionController.resolveContentDownloadAction(
@@ -31664,6 +33204,7 @@ var ListTableHeaderActionController = class {
31664
33204
  if (this.options.isEditing() || this.options.getLeafColumns().find((column) => column.key === columnKey)?.allowSort === false) {
31665
33205
  return;
31666
33206
  }
33207
+ this.options.captureSortAnimation?.(columnKey);
31667
33208
  this.options.prepareLocalQuery("sort");
31668
33209
  this.options.setSortState(
31669
33210
  toggleSortingState(
@@ -31681,6 +33222,7 @@ var ListTableHeaderActionController = class {
31681
33222
  if (this.options.isEditing() || this.options.getLeafColumns().find((column) => column.key === columnKey)?.allowSort === false) {
31682
33223
  return;
31683
33224
  }
33225
+ this.options.captureSortAnimation?.(columnKey);
31684
33226
  this.options.prepareLocalQuery("sort");
31685
33227
  this.options.setSortState(
31686
33228
  setSortingOrder(
@@ -31851,6 +33393,7 @@ var ListTableHeaderActionController = class {
31851
33393
  if (this.options.isEditing()) {
31852
33394
  return;
31853
33395
  }
33396
+ this.options.captureSortAnimation?.();
31854
33397
  this.options.prepareLocalQuery("sort");
31855
33398
  const next = resolveResetSortAction(this.options.getFilterState());
31856
33399
  this.options.setSortState(next.sortState);
@@ -31888,6 +33431,7 @@ var ListTableHeaderActionController = class {
31888
33431
  if (!resolved) {
31889
33432
  return;
31890
33433
  }
33434
+ this.options.overlayController.preserveHeaderContextMenuForColumnVisibility();
31891
33435
  this.options.setSelectedHeaderState(
31892
33436
  resolved.selectedHeaderKey,
31893
33437
  resolved.selectedHeaderRect
@@ -31912,6 +33456,9 @@ var ListTableHeaderActionController = class {
31912
33456
  buildHeaderSettingsItems(columns)
31913
33457
  );
31914
33458
  this.options.requestRender();
33459
+ if (draft.key && draft.sortOrder !== void 0 && (this.options.getSortState().find((entry) => entry.key === draft.key)?.order ?? null) !== draft.sortOrder) {
33460
+ this.setSortOrder(draft.key, draft.sortOrder);
33461
+ }
31915
33462
  return null;
31916
33463
  }
31917
33464
  deleteHeaderColumn(columnKey) {
@@ -32003,6 +33550,7 @@ var ListTableOverlayController = class {
32003
33550
  __publicField(this, "componentPortal");
32004
33551
  __publicField(this, "getContentZoom");
32005
33552
  __publicField(this, "runtime");
33553
+ __publicField(this, "preserveColumnVisibilityMenu", false);
32006
33554
  __publicField(this, "tooltipAdapter");
32007
33555
  __publicField(this, "filterPanelAdapter");
32008
33556
  __publicField(this, "fixedPopupAdapter");
@@ -32140,6 +33688,7 @@ var ListTableOverlayController = class {
32140
33688
  return this.componentPortal.fixedPopup.isVisible();
32141
33689
  }
32142
33690
  showHeaderContextMenu(config) {
33691
+ this.preserveColumnVisibilityMenu = false;
32143
33692
  this.runtime.headerContextMenuVisible = true;
32144
33693
  this.runtime.headerContextMenuConfig = config;
32145
33694
  const options = this.getOptions();
@@ -32149,6 +33698,7 @@ var ListTableOverlayController = class {
32149
33698
  }
32150
33699
  }
32151
33700
  hideHeaderContextMenu() {
33701
+ this.preserveColumnVisibilityMenu = false;
32152
33702
  this.runtime.headerContextMenuVisible = false;
32153
33703
  this.runtime.headerContextMenuConfig = null;
32154
33704
  this.getOptions().ui?.onHeaderContextMenuRequest?.(null);
@@ -32160,6 +33710,15 @@ var ListTableOverlayController = class {
32160
33710
  }
32161
33711
  return this.componentPortal.headerContextMenu.isVisible();
32162
33712
  }
33713
+ /** 连续修改列显隐时,保留菜单直到用户显式关闭。 */
33714
+ preserveHeaderContextMenuForColumnVisibility() {
33715
+ if (this.runtime.headerContextMenuVisible) {
33716
+ this.preserveColumnVisibilityMenu = true;
33717
+ }
33718
+ }
33719
+ shouldPreserveHeaderContextMenuOnOptionsUpdate() {
33720
+ return this.runtime.headerContextMenuVisible && this.preserveColumnVisibilityMenu;
33721
+ }
32163
33722
  updateHeaderContextMenuColumns(columns) {
32164
33723
  const options = this.getOptions();
32165
33724
  if (options.ui?.onHeaderContextMenuRequest && this.runtime.headerContextMenuConfig) {
@@ -32380,7 +33939,7 @@ function applyStoredColumnConfig(columns, storedColumns, cacheColumnSettings = t
32380
33939
  applyToColumns(columns);
32381
33940
  return columnWidthsChanged;
32382
33941
  }
32383
- function buildStoredColumnConfig(columns, sortState, filterState, zoom, summaryRowHeight, density, cacheColumnSettings = true, cachePreferences) {
33942
+ function buildStoredColumnConfig(columns, sortState, filterState, zoom, summaryRowHeight, density, cacheColumnSettings = true, cachePreferences, scrollbar) {
32384
33943
  const result = {};
32385
33944
  const columnOrder = [];
32386
33945
  const collectColumns = (cols, parentKey) => {
@@ -32437,6 +33996,7 @@ function buildStoredColumnConfig(columns, sortState, filterState, zoom, summaryR
32437
33996
  {
32438
33997
  columns: result,
32439
33998
  cacheColumnSettings,
33999
+ ...scrollbar ? { scrollbar } : null,
32440
34000
  ...cacheColumnSettings ? { columnOrder } : null,
32441
34001
  sort: sortState.map((item) => ({ ...item })),
32442
34002
  filters: filterState,
@@ -32476,6 +34036,7 @@ function filterStoredColumnConfig(stored, preferences = {}) {
32476
34036
  if (preferences.summary === false) delete result.summaryRowHeight;
32477
34037
  if (preferences.density === false) delete result.density;
32478
34038
  if (preferences.zoom === false) delete result.zoom;
34039
+ if (preferences.scrollbar === false) delete result.scrollbar;
32479
34040
  return result;
32480
34041
  }
32481
34042
 
@@ -32490,7 +34051,8 @@ function persistListTableColumnConfig(params) {
32490
34051
  summaryRowHeight,
32491
34052
  density,
32492
34053
  cacheColumnSettings,
32493
- cachePreferences
34054
+ cachePreferences,
34055
+ scrollbar
32494
34056
  } = params;
32495
34057
  if (!storageKey) {
32496
34058
  return;
@@ -32506,7 +34068,8 @@ function persistListTableColumnConfig(params) {
32506
34068
  summaryRowHeight,
32507
34069
  density,
32508
34070
  cacheColumnSettings,
32509
- cachePreferences
34071
+ cachePreferences,
34072
+ scrollbar
32510
34073
  )
32511
34074
  );
32512
34075
  }
@@ -32575,6 +34138,7 @@ async function loadListTableStoredConfig(params) {
32575
34138
  stored.columnOrder
32576
34139
  );
32577
34140
  return {
34141
+ scrollbar: stored.scrollbar,
32578
34142
  cacheColumnSettings,
32579
34143
  cachePreferences,
32580
34144
  sortState: cachePreferences.sort !== false && Array.isArray(stored.sort) ? stored.sort.filter(
@@ -32659,6 +34223,10 @@ var ListTablePersistenceController = class {
32659
34223
  this.options.canvasHost.setContentZoom(nextZoom);
32660
34224
  }
32661
34225
  let currentOptions = this.options.getOptions();
34226
+ if (stored.scrollbar) {
34227
+ currentOptions = { ...currentOptions, scrollbar: stored.scrollbar };
34228
+ currentOptions.ui?.onScrollbarChange?.(stored.scrollbar);
34229
+ }
32662
34230
  if (stored.cachePreferences) {
32663
34231
  currentOptions = {
32664
34232
  ...currentOptions,
@@ -32703,10 +34271,16 @@ var ListTablePersistenceController = class {
32703
34271
  }
32704
34272
  }
32705
34273
  this.options.refreshRuntimeColumns();
34274
+ currentOptions.ui?.onColumnSettingsChange?.(
34275
+ cloneColumns(currentOptions.columns)
34276
+ );
32706
34277
  }
32707
34278
  persistColumnConfig() {
32708
34279
  this.invalidate();
32709
34280
  const tableOptions = this.options.getOptions();
34281
+ tableOptions.ui?.onColumnSettingsChange?.(
34282
+ cloneColumns(tableOptions.columns)
34283
+ );
32710
34284
  this.restoredStorageKey = tableOptions.storageKey;
32711
34285
  this.hasRestoredPreferences = true;
32712
34286
  this.pendingWrite = Promise.resolve(
@@ -32714,6 +34288,7 @@ var ListTablePersistenceController = class {
32714
34288
  storageKey: tableOptions.storageKey,
32715
34289
  cacheColumnSettings: tableOptions.cacheColumnSettings,
32716
34290
  cachePreferences: tableOptions.cachePreferences,
34291
+ scrollbar: tableOptions.scrollbar,
32717
34292
  columns: tableOptions.columns,
32718
34293
  sortState: this.options.getSortState(),
32719
34294
  filterState: this.options.getFilterState(),
@@ -32948,6 +34523,7 @@ var ListTableQueryController = class {
32948
34523
  this.invalidateDataCache();
32949
34524
  this.options.hideLoading();
32950
34525
  this.emitQueryChangeWithResolvedRows(action, baseRows);
34526
+ if (action === "sort") this.options.onSortResolved?.();
32951
34527
  this.options.requestRender();
32952
34528
  }).catch(handleFailure);
32953
34529
  };
@@ -34472,6 +36048,7 @@ var ListTableSelectionController = class {
34472
36048
  __publicField(this, "selectedHeaderKey", null);
34473
36049
  __publicField(this, "selectedHeaderRect", null);
34474
36050
  __publicField(this, "summarySelected", false);
36051
+ __publicField(this, "pendingSortSelection", null);
34475
36052
  this.options = options;
34476
36053
  }
34477
36054
  getSelectedHeaderKey() {
@@ -34495,20 +36072,62 @@ var ListTableSelectionController = class {
34495
36072
  this.selectedHeaderRect = null;
34496
36073
  }
34497
36074
  clearBodySelection() {
36075
+ this.pendingSortSelection = null;
34498
36076
  this.options.setSelection({
34499
36077
  rowIndex: null,
34500
36078
  columnKey: null
34501
36079
  });
34502
36080
  }
36081
+ /** 排序前按稳定行标识记录活动行,避免行号被新排序复用。 */
36082
+ captureSortSelection(rows) {
36083
+ const options = this.options.getOptions();
36084
+ const rowIndex = this.options.getSelection().rowIndex;
36085
+ const record = rowIndex == null ? void 0 : rows[rowIndex];
36086
+ this.pendingSortSelection = options.rowKey && record !== void 0 && rowIndex != null ? { rowKey: getRowKey(options, record, rowIndex), rowIndex } : null;
36087
+ }
36088
+ /** 排序完成后将活动行及其单行选区映射到新行号。 */
36089
+ reconcileSortSelection(rows) {
36090
+ const pending = this.pendingSortSelection;
36091
+ this.pendingSortSelection = null;
36092
+ if (!pending) return;
36093
+ const options = this.options.getOptions();
36094
+ const sameIndexRecord = rows[pending.rowIndex];
36095
+ const nextIndex = sameIndexRecord !== void 0 && getRowKey(options, sameIndexRecord, pending.rowIndex) === pending.rowKey ? pending.rowIndex : rows.findIndex(
36096
+ (record, index) => getRowKey(options, record, index) === pending.rowKey
36097
+ );
36098
+ const selection = this.options.getSelection();
36099
+ if (selection.rowIndex !== pending.rowIndex) return;
36100
+ if (nextIndex === pending.rowIndex) return;
36101
+ this.options.setSelection({
36102
+ ...selection,
36103
+ rowIndex: nextIndex >= 0 ? nextIndex : null,
36104
+ columnKey: nextIndex >= 0 ? selection.columnKey : null
36105
+ });
36106
+ const range = this.options.getRangeHighlight();
36107
+ const singleRowRange = range.selectedRowRange?.start === pending.rowIndex && range.selectedRowRange.end === pending.rowIndex;
36108
+ const singleCellRange = range.selectedCellRange?.startRowIndex === pending.rowIndex && range.selectedCellRange.endRowIndex === pending.rowIndex;
36109
+ this.options.setRangeHighlight({
36110
+ ...range,
36111
+ selectedRowAnchorIndex: range.selectedRowAnchorIndex === pending.rowIndex ? nextIndex >= 0 ? nextIndex : null : range.selectedRowAnchorIndex,
36112
+ selectedRowRange: singleRowRange ? nextIndex >= 0 ? { start: nextIndex, end: nextIndex } : null : range.selectedRowRange,
36113
+ selectedCellAnchor: range.selectedCellAnchor?.rowIndex === pending.rowIndex ? nextIndex >= 0 ? { ...range.selectedCellAnchor, rowIndex: nextIndex } : null : range.selectedCellAnchor,
36114
+ selectedCellRange: singleCellRange ? nextIndex >= 0 ? {
36115
+ ...range.selectedCellRange,
36116
+ startRowIndex: nextIndex,
36117
+ endRowIndex: nextIndex
36118
+ } : null : range.selectedCellRange
36119
+ });
36120
+ }
34503
36121
  setSelectedHeaderState(selectedHeaderKey, selectedHeaderRect) {
34504
36122
  this.selectedHeaderKey = selectedHeaderKey;
34505
36123
  this.selectedHeaderRect = selectedHeaderRect;
34506
36124
  }
34507
- resetRangeHighlightForHeaderSelection(shiftKey) {
36125
+ resetRangeHighlightForHeaderSelection(shiftKey, ctrlKey = false) {
34508
36126
  this.options.setRangeHighlight(
34509
36127
  resolveRangeHighlightForHeaderSelection({
34510
36128
  current: this.options.getRangeHighlight(),
34511
- shiftKey
36129
+ shiftKey,
36130
+ ctrlKey
34512
36131
  })
34513
36132
  );
34514
36133
  }
@@ -34576,7 +36195,7 @@ var ListTableSelectionController = class {
34576
36195
  })
34577
36196
  );
34578
36197
  }
34579
- updateRangeHighlightForHeaderClick(columnKey, shiftKey) {
36198
+ updateRangeHighlightForHeaderClick(columnKey, shiftKey, ctrlKey = false) {
34580
36199
  const leafColumns = this.options.getLeafColumns();
34581
36200
  const targetRange = findHeaderLeafRange({
34582
36201
  columnKey,
@@ -34593,7 +36212,8 @@ var ListTableSelectionController = class {
34593
36212
  leafColumnKeys: leafColumns.map((column) => column.key),
34594
36213
  rangeStartIndex: targetRange.start,
34595
36214
  rangeEndIndex: targetRange.end,
34596
- shiftKey
36215
+ shiftKey,
36216
+ ctrlKey
34597
36217
  })
34598
36218
  );
34599
36219
  }
@@ -34637,7 +36257,8 @@ var ListTableSelectionController = class {
34637
36257
  this.options.setRangeHighlight({
34638
36258
  ...current,
34639
36259
  selectedColumnAnchorKey: null,
34640
- selectedColumnRange: null
36260
+ selectedColumnRange: null,
36261
+ selectedColumnKeys: null
34641
36262
  });
34642
36263
  }
34643
36264
  destroy() {
@@ -34975,6 +36596,44 @@ function createDefaultSummaryScheduler() {
34975
36596
  };
34976
36597
  }
34977
36598
 
36599
+ // src/engine/sort-animation.ts
36600
+ function hasAnimatedSortColumn(columns, sortState) {
36601
+ if (!sortState.length) return false;
36602
+ const activeKeys = new Set(sortState.map((item) => item.key));
36603
+ const visit = (items) => items.some(
36604
+ (column) => activeKeys.has(resolveColumnKey(column)) && typeof column.sorter === "object" && column.sorter.animation === true || (column.children?.length ? visit(column.children) : false)
36605
+ );
36606
+ return visit(columns);
36607
+ }
36608
+ function shouldAnimateSortedDataUpdate(params) {
36609
+ const { previous, next, sortState, expandedRowsChanged } = params;
36610
+ return Boolean(
36611
+ !expandedRowsChanged && next.rowKey && previous.rowKey && previous.rowHeight !== "auto" && next.rowHeight !== "auto" && next.rowHeight === previous.rowHeight && next.dataSource !== previous.dataSource && hasAnimatedSortColumn(next.columns, sortState)
36612
+ );
36613
+ }
36614
+
36615
+ // src/features/grouping/default-grouping.ts
36616
+ function resolveDefaultGroupingColumnKeys(columns) {
36617
+ const candidates = [];
36618
+ const visit = (items) => {
36619
+ items.forEach((column) => {
36620
+ if (column.children?.length) {
36621
+ visit(column.children);
36622
+ return;
36623
+ }
36624
+ if (!column.grouping) return;
36625
+ const order = typeof column.grouping === "object" && Number.isFinite(column.grouping.order) ? column.grouping.order : Number.POSITIVE_INFINITY;
36626
+ candidates.push({
36627
+ key: column.key ?? String(column.dataIndex),
36628
+ order,
36629
+ index: candidates.length
36630
+ });
36631
+ });
36632
+ };
36633
+ visit(columns);
36634
+ return candidates.sort((left, right) => left.order - right.order || left.index - right.index).map((item) => item.key);
36635
+ }
36636
+
34978
36637
  // src/engine/controller-assembly.ts
34979
36638
  function assembleListTableCoreControllers(core, options) {
34980
36639
  const getCanvasHostElement = () => core.domHost.getNodes()?.canvasHostElement ?? null;
@@ -35098,14 +36757,24 @@ function assembleListTableCoreControllers(core, options) {
35098
36757
  ...core.storeFacade.rangeHighlight,
35099
36758
  selectedColumnAnchorKey: null,
35100
36759
  selectedColumnRange: null,
36760
+ selectedColumnKeys: null,
35101
36761
  selectedCellRange: null
35102
36762
  };
35103
36763
  };
35104
36764
  core.syncGroupingBar = syncGroupingBar;
35105
36765
  core.syncGroupingFromOptions = () => {
35106
36766
  const previousColumnKeys = core.groupColumnKeys;
36767
+ const nextDefaultKeys = resolveDefaultGroupingColumnKeys(
36768
+ core.options.columns
36769
+ );
36770
+ const defaultsChanged = nextDefaultKeys.length !== core.defaultGroupColumnKeys.length || nextDefaultKeys.some(
36771
+ (key, index) => key !== core.defaultGroupColumnKeys[index]
36772
+ );
36773
+ core.defaultGroupColumnKeys = nextDefaultKeys;
35107
36774
  if (core.options.grouping?.visible !== void 0) {
35108
36775
  core.groupBarVisible = core.options.grouping.visible;
36776
+ } else if (defaultsChanged) {
36777
+ core.groupBarVisible = nextDefaultKeys.length > 0;
35109
36778
  }
35110
36779
  if (core.options.grouping?.columnKeys !== void 0) {
35111
36780
  const validKeys = new Set(
@@ -35116,6 +36785,8 @@ function assembleListTableCoreControllers(core, options) {
35116
36785
  core.groupColumnKeys = core.options.grouping.columnKeys.filter(
35117
36786
  (key, index, keys) => validKeys.has(key) && keys.indexOf(key) === index
35118
36787
  );
36788
+ } else if (defaultsChanged) {
36789
+ core.groupColumnKeys = nextDefaultKeys;
35119
36790
  }
35120
36791
  if (previousColumnKeys.length !== core.groupColumnKeys.length || previousColumnKeys.some(
35121
36792
  (key, index) => key !== core.groupColumnKeys[index]
@@ -35196,7 +36867,8 @@ function assembleListTableCoreControllers(core, options) {
35196
36867
  getQueryRuntimeState,
35197
36868
  showLoading: (text) => core.overlayController.showLoading(text),
35198
36869
  hideLoading: () => core.overlayController.hideLoading(),
35199
- requestRender: () => render()
36870
+ requestRender: () => render(),
36871
+ onSortResolved: () => core.animationController.markSortRowsReady()
35200
36872
  });
35201
36873
  core.summaryController = new ListTableSummaryController({
35202
36874
  getOptions: () => core.options,
@@ -35351,6 +37023,18 @@ function assembleListTableCoreControllers(core, options) {
35351
37023
  persistColumnConfig: () => core.persistenceController.persistColumnConfig(),
35352
37024
  emitQueryChange,
35353
37025
  prepareLocalQuery,
37026
+ captureSortAnimation: (columnKey) => {
37027
+ const currentSort = core.storeFacade.sortState;
37028
+ const nextSort = columnKey ? [...currentSort, { key: columnKey, order: "ascend" }] : currentSort;
37029
+ if (!core.options.rowKey || core.options.rowHeight === "auto" || !hasAnimatedSortColumn(core.options.columns, nextSort)) {
37030
+ core.animationController.setPendingSortRowPositions(null);
37031
+ return;
37032
+ }
37033
+ core.selectionController.captureSortSelection(getDisplayData());
37034
+ core.animationController.setPendingSortRowPositions(
37035
+ captureRenderedVisibleRowPositions(getCurrentRenderSnapshot())
37036
+ );
37037
+ },
35354
37038
  applyFilterQueryAsync,
35355
37039
  applySortQueryAsync,
35356
37040
  refreshRuntimeColumns,
@@ -35366,6 +37050,7 @@ function assembleListTableCoreControllers(core, options) {
35366
37050
  });
35367
37051
  core.contentActionController = new ListTableContentActionController({
35368
37052
  getSummaryVisible: () => Boolean(getCurrentRenderSnapshot()?.hasSummary),
37053
+ getSortState: () => core.storeFacade.sortState,
35369
37054
  getOptions: () => core.options,
35370
37055
  getLeafColumns: () => core.leafColumns,
35371
37056
  overlayController: core.overlayController,
@@ -35510,6 +37195,9 @@ function assembleListTableCoreControllers(core, options) {
35510
37195
  expandedRowKeys: core.storeFacade.expandedRowKeys
35511
37196
  });
35512
37197
  core.animationController.reconcileCollapseAnimations(snapshot);
37198
+ if (core.animationController.reconcileSortAnimations(snapshot)) {
37199
+ core.selectionController.reconcileSortSelection(snapshot.displayRows);
37200
+ }
35513
37201
  },
35514
37202
  getPublishAccessors: () => ({
35515
37203
  nestedTableLayoutRevision: core.animationController.getNestedTableLayoutRevision(),
@@ -35678,8 +37366,13 @@ function assembleListTableCoreControllers(core, options) {
35678
37366
  core.draggingResize = null;
35679
37367
  core.draggingReorder = null;
35680
37368
  core.suppressNextClick = false;
35681
- core.groupBarVisible = options.grouping?.visible ?? false;
35682
- core.groupColumnKeys = [...options.grouping?.columnKeys ?? []];
37369
+ core.defaultGroupColumnKeys = resolveDefaultGroupingColumnKeys(
37370
+ options.columns
37371
+ );
37372
+ core.groupBarVisible = options.grouping?.visible ?? core.defaultGroupColumnKeys.length > 0;
37373
+ core.groupColumnKeys = [
37374
+ ...options.grouping?.columnKeys ?? core.defaultGroupColumnKeys
37375
+ ];
35683
37376
  core.tableZoom = 1;
35684
37377
  }
35685
37378
  function collectGroupingColumnItems(columns) {
@@ -35794,6 +37487,7 @@ var ListTableCore = class {
35794
37487
  * @param options 新配置。
35795
37488
  */
35796
37489
  updateOptions(options) {
37490
+ const preserveContextMenu = options.dataSource !== this.options.dataSource || this.overlayController.shouldPreserveHeaderContextMenuOnOptionsUpdate();
35797
37491
  this.persistenceController.invalidate();
35798
37492
  if (options.storageKey === this.options.storageKey) {
35799
37493
  options = {
@@ -35805,6 +37499,8 @@ var ListTableCore = class {
35805
37499
  options = resolveListTableStyleOptions(options);
35806
37500
  this.animationController.stopCarouselScroll();
35807
37501
  const host = this.asAssemblyHost();
37502
+ const previousLeafColumns = host.leafColumns;
37503
+ const previousSegments = host.columnSegments;
35808
37504
  const shouldResetColumnConfig = shouldPersistIncomingColumnConfig(
35809
37505
  this.options.columnConfigResetRevision,
35810
37506
  options.columnConfigResetRevision
@@ -35833,15 +37529,37 @@ var ListTableCore = class {
35833
37529
  }
35834
37530
  applyInitialColumnVisibility(options.columns);
35835
37531
  ensureColumnKeysInPlace(options.columns);
35836
- if (options.expandable?.expandedRowKeys !== void 0 && !areSameRowKeySet(
37532
+ const expandedRowsChanged = options.expandable?.expandedRowKeys !== void 0 && !areSameRowKeySet(
35837
37533
  this.storeFacade.expandedRowKeys,
35838
37534
  options.expandable.expandedRowKeys
35839
- )) {
37535
+ );
37536
+ if (expandedRowsChanged) {
35840
37537
  this.animationController.setPendingCollapseRowPositions(
35841
37538
  captureRenderedVisibleRowPositions(
35842
37539
  this.renderController.getCurrentRenderSnapshot()
35843
37540
  )
35844
37541
  );
37542
+ } else if (shouldAnimateSortedDataUpdate({
37543
+ previous: this.options,
37544
+ next: options,
37545
+ sortState: this.storeFacade.sortState,
37546
+ expandedRowsChanged
37547
+ })) {
37548
+ if (this.animationController.hasPendingSortRows()) {
37549
+ this.animationController.markSortRowsReady();
37550
+ } else {
37551
+ this.selectionController.captureSortSelection(
37552
+ this.queryController.getDisplayData()
37553
+ );
37554
+ this.animationController.setPendingSortRowPositions(
37555
+ captureRenderedVisibleRowPositions(
37556
+ this.renderController.getCurrentRenderSnapshot()
37557
+ ),
37558
+ true
37559
+ );
37560
+ }
37561
+ } else if (options.dataSource !== this.options.dataSource) {
37562
+ this.animationController.markSortRowsReady();
35845
37563
  }
35846
37564
  this.queryController.reset();
35847
37565
  this.options = options;
@@ -35859,7 +37577,10 @@ var ListTableCore = class {
35859
37577
  });
35860
37578
  this.debugManager = new DebugManager(options.debug);
35861
37579
  host.renderer?.updateDebugOptions(options.debug ?? {});
35862
- this.hideFloatingOverlays({ includeLoading: true });
37580
+ this.hideFloatingOverlays({
37581
+ includeLoading: true,
37582
+ preserveContextMenu
37583
+ });
35863
37584
  this.refreshRuntimeColumns();
35864
37585
  if (shouldPersistColumnConfig) {
35865
37586
  this.persistenceController.persistColumnConfig();
@@ -35867,6 +37588,12 @@ var ListTableCore = class {
35867
37588
  this.persistenceController.loadStoredConfig({ restoreQueryState: false });
35868
37589
  }
35869
37590
  this.renderController.render();
37591
+ if (shouldPersistColumnConfig && haveVisibleLeafColumnsChanged(previousLeafColumns, host.leafColumns)) {
37592
+ host.rowActionController.startColumnVisibilityAnimation({
37593
+ previousLeafColumns,
37594
+ previousSegments
37595
+ });
37596
+ }
35870
37597
  host.tableId = options.tableId?.trim() ? options.tableId : host.tableId;
35871
37598
  host.rowDragController.syncRegistration();
35872
37599
  }
@@ -35904,6 +37631,14 @@ var ListTableCore = class {
35904
37631
  resetSorter() {
35905
37632
  this.headerActionController.resetSort();
35906
37633
  }
37634
+ /** 获取当前排序状态,供外部设置面板回显。 */
37635
+ getSortState() {
37636
+ return [...this.storeFacade.sortState];
37637
+ }
37638
+ /** 使用与表头一致的排序逻辑设置指定列。 */
37639
+ setSortOrder(columnKey, order) {
37640
+ this.headerActionController.setSortOrder(columnKey, order);
37641
+ }
35907
37642
  /**
35908
37643
  * 重置筛选状态。
35909
37644
  */
@@ -36009,14 +37744,15 @@ var ListTableCore = class {
36009
37744
  return this;
36010
37745
  }
36011
37746
  hideFloatingOverlays(params) {
36012
- this.componentPortal.hideFloatingLayers();
36013
37747
  if (params?.includeLoading) {
36014
37748
  this.overlayController.hideLoading();
36015
37749
  }
36016
37750
  this.overlayController.hideTooltip();
36017
37751
  this.overlayController.hideFilterPanel();
36018
37752
  this.overlayController.hideFixedPopup();
36019
- this.overlayController.hideHeaderContextMenu();
37753
+ if (!params?.preserveContextMenu) {
37754
+ this.overlayController.hideHeaderContextMenu();
37755
+ }
36020
37756
  }
36021
37757
  refreshRuntimeColumns() {
36022
37758
  this.storeFacade.runtimeColumns = buildRuntimeColumnsMap({
@@ -36098,6 +37834,14 @@ var ListTable = class {
36098
37834
  resetSorter() {
36099
37835
  this.core?.resetSorter();
36100
37836
  }
37837
+ /** 获取当前排序状态。 */
37838
+ getSortState() {
37839
+ return this.core?.getSortState() ?? [];
37840
+ }
37841
+ /** 设置指定列的排序方式。 */
37842
+ setSortOrder(columnKey, order) {
37843
+ this.core?.setSortOrder(columnKey, order);
37844
+ }
36101
37845
  /**
36102
37846
  * 重置筛选状态。
36103
37847
  */