@canvas-components/list-table 0.3.38 → 0.3.40

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 { formatPreciseNumber, addPreciseNumbers, comparePreciseNumbers, dividePreciseNumber, getValueByDataIndex, roundPreciseNumber, isSameDataIndex, stringifyDataIndex, resolveCanvasScrollbarAxis, clamp, copyTextSync, copyText, resolveCanvasScrollbarHoldSpeed, exportTableToXlsx, exportTableToTxt, exportTableToCsv, mapRowsToExportRecords, downloadJsonFile, copyJson, copyRows, isDateTimeFormatPattern, parseNumberValue, formatNumberValue, formatPercentValue, formatScientificValue, formatChineseNumber, parseChineseNumber, normalizeDecimalPlaces, formatDateTimeValue, formatCustomNumberPattern, isPointInRect as isPointInRect$1 } from '@canvas-components/utils';
1
+ import { formatPreciseNumber, addPreciseNumbers, comparePreciseNumbers, dividePreciseNumber, getValueByDataIndex, roundPreciseNumber, isSameDataIndex, stringifyDataIndex, resolveCanvasScrollbarAxis, clamp, copyTextSync, copyText, resolveCanvasScrollbarHoldSpeed, exportTableToXlsx, mapInBatches, exportTableToTxt, exportTableToCsv, mapRowsToExportRecords, downloadJsonFile, copyJson, copyRows, isDateTimeFormatPattern, parseNumberValue, formatNumberValue, formatPercentValue, formatScientificValue, formatChineseNumber, parseChineseNumber, normalizeDecimalPlaces, 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 { iconNames, getIconDefinition } from '@canvas-components/icons';
@@ -1682,7 +1682,7 @@ var ListTableDomHost = class {
1682
1682
  wrapper.style.position = "relative";
1683
1683
  wrapper.style.display = "flex";
1684
1684
  wrapper.style.flexDirection = "column";
1685
- wrapper.style.minWidth = "0";
1685
+ wrapper.style.minWidth = "0px";
1686
1686
  wrapper.style.maxWidth = "100%";
1687
1687
  wrapper.style.boxSizing = "border-box";
1688
1688
  wrapper.style.overflow = "visible";
@@ -1691,7 +1691,7 @@ var ListTableDomHost = class {
1691
1691
  contentLayer.style.display = "flex";
1692
1692
  contentLayer.style.flexDirection = "column";
1693
1693
  contentLayer.style.flex = "1 1 auto";
1694
- contentLayer.style.minWidth = "0";
1694
+ contentLayer.style.minWidth = "0px";
1695
1695
  contentLayer.style.width = "100%";
1696
1696
  contentLayer.style.boxSizing = "border-box";
1697
1697
  contentLayer.style.minHeight = "0";
@@ -1699,7 +1699,7 @@ var ListTableDomHost = class {
1699
1699
  const canvasHost = document.createElement("div");
1700
1700
  canvasHost.style.position = "relative";
1701
1701
  canvasHost.style.flex = "1 1 auto";
1702
- canvasHost.style.minWidth = "0";
1702
+ canvasHost.style.minWidth = "0px";
1703
1703
  canvasHost.style.width = "100%";
1704
1704
  canvasHost.style.boxSizing = "border-box";
1705
1705
  canvasHost.style.minHeight = "0";
@@ -3195,6 +3195,7 @@ function hitTest(x, y, descriptors) {
3195
3195
  resizeEdge: matched.resizeEdge,
3196
3196
  cursor: matched.cursor,
3197
3197
  rect: interactionRect,
3198
+ tooltipRect: resolveErrorTooltipRect(matched, owningCells),
3198
3199
  tooltipText: matched.tooltipText,
3199
3200
  tooltipVariant: matched.tooltipVariant,
3200
3201
  textSelectionText: matched.textSelectionText,
@@ -3209,6 +3210,18 @@ function hitTest(x, y, descriptors) {
3209
3210
  scrollbarRole: matched.scrollbarRole
3210
3211
  };
3211
3212
  }
3213
+ function resolveErrorTooltipRect(descriptor, owningCells) {
3214
+ if (descriptor.tooltipVariant !== "error") {
3215
+ return void 0;
3216
+ }
3217
+ if (descriptor.kind === "body") {
3218
+ return descriptor.rect;
3219
+ }
3220
+ const candidates = owningCells.get(buildOwningCellKey(descriptor))?.filter((cell) => cell.kind === "body");
3221
+ return (candidates?.find(
3222
+ (cell) => cell.fixed === descriptor.fixed && cell.frozen === descriptor.frozen
3223
+ ) ?? candidates?.[0])?.rect;
3224
+ }
3212
3225
  function resolveInteractionRect(matched, descriptors) {
3213
3226
  if (matched.contentKey !== "nested-table" || typeof matched.nestedRowIndex !== "number" || typeof matched.nestedColumnIndex !== "number" || matched.debugNodeType === "nested-table-cell") {
3214
3227
  return matched.rect;
@@ -3283,6 +3296,7 @@ function mapKindToArea(kind, actionType) {
3283
3296
  if (kind === "grouping-remove") {
3284
3297
  return "grouping-remove";
3285
3298
  }
3299
+ if (kind === "group-toggle") return "group-toggle";
3286
3300
  if (kind === "body") {
3287
3301
  return "body";
3288
3302
  }
@@ -3363,6 +3377,8 @@ function getBasePriority(kind) {
3363
3377
  return 5;
3364
3378
  case "grouping-bar":
3365
3379
  return 2;
3380
+ case "group-toggle":
3381
+ return 3;
3366
3382
  case "resize-handle":
3367
3383
  return 4;
3368
3384
  // 折叠列图标覆盖列宽热区,但仍低于固定列表头的遮挡层(优先级 5)。
@@ -3405,6 +3421,7 @@ var BodyTooltipController = class {
3405
3421
  __publicField(this, "toViewportPoint");
3406
3422
  __publicField(this, "timer", null);
3407
3423
  __publicField(this, "tooltipKey", null);
3424
+ __publicField(this, "tooltipPoint", null);
3408
3425
  this.tooltip = options.tooltip;
3409
3426
  this.delay = options.delay;
3410
3427
  this.toViewportPoint = options.toViewportPoint;
@@ -3428,6 +3445,7 @@ var BodyTooltipController = class {
3428
3445
  this.timer = null;
3429
3446
  }
3430
3447
  this.tooltipKey = null;
3448
+ this.tooltipPoint = null;
3431
3449
  if (hideTooltip) {
3432
3450
  this.tooltip.hide();
3433
3451
  }
@@ -3437,17 +3455,24 @@ var BodyTooltipController = class {
3437
3455
  return false;
3438
3456
  }
3439
3457
  if (result.tooltipVariant === "error") {
3440
- this.clear();
3441
- this.tooltipKey = `${result.rowIndex}:${result.columnKey}:${result.tooltipText}`;
3458
+ const rect = result.tooltipRect ?? result.rect;
3459
+ const tooltipKey2 = `${result.rowIndex}:${result.columnKey}:${result.tooltipText}`;
3442
3460
  const tooltipPoint = this.toViewportPoint(
3443
- result.rect.x + result.rect.width / 2,
3444
- result.rect.y + result.rect.height + 8
3461
+ rect.x + rect.width / 2,
3462
+ rect.y + rect.height + 8
3445
3463
  );
3464
+ if (this.tooltipKey === tooltipKey2 && this.tooltipPoint?.x === tooltipPoint.x && this.tooltipPoint.y === tooltipPoint.y) {
3465
+ return true;
3466
+ }
3467
+ this.clear();
3468
+ this.tooltipKey = tooltipKey2;
3469
+ this.tooltipPoint = tooltipPoint;
3446
3470
  this.tooltip.show(
3447
3471
  tooltipPoint.x,
3448
3472
  tooltipPoint.y,
3449
3473
  result.tooltipText,
3450
- "error"
3474
+ "error",
3475
+ this.toViewportRect(rect)
3451
3476
  );
3452
3477
  return true;
3453
3478
  }
@@ -3469,12 +3494,26 @@ var BodyTooltipController = class {
3469
3494
  tooltipPoint.x,
3470
3495
  tooltipPoint.y,
3471
3496
  result.tooltipText,
3472
- result.tooltipVariant
3497
+ result.tooltipVariant,
3498
+ this.toViewportRect(result.rect)
3473
3499
  );
3474
3500
  this.timer = null;
3475
3501
  }, this.delay);
3476
3502
  return true;
3477
3503
  }
3504
+ toViewportRect(rect) {
3505
+ const topLeft = this.toViewportPoint(rect.x, rect.y);
3506
+ const bottomRight = this.toViewportPoint(
3507
+ rect.x + rect.width,
3508
+ rect.y + rect.height
3509
+ );
3510
+ return {
3511
+ x: topLeft.x,
3512
+ y: topLeft.y,
3513
+ width: bottomRight.x - topLeft.x,
3514
+ height: bottomRight.y - topLeft.y
3515
+ };
3516
+ }
3478
3517
  };
3479
3518
 
3480
3519
  // src/features/scroll/scroll-session.ts
@@ -9760,32 +9799,39 @@ function drawBody(params) {
9760
9799
  scrollTop: params.scroll.top,
9761
9800
  rowOffsets
9762
9801
  });
9763
- drawSegmentRows(
9764
- params,
9765
- "center",
9766
- params.centerColumns,
9767
- startRowIndex,
9768
- endRowIndex,
9769
- rowOffsets
9770
- );
9771
- drawSegmentRows(
9772
- params,
9773
- "left",
9774
- params.leftColumns,
9775
- startRowIndex,
9776
- endRowIndex,
9777
- rowOffsets
9778
- );
9779
- drawSegmentRows(
9780
- params,
9781
- "right",
9782
- params.rightColumns,
9783
- startRowIndex,
9784
- endRowIndex,
9785
- rowOffsets
9786
- );
9787
- drawGroupRowsOverlay(params, startRowIndex, endRowIndex, rowOffsets);
9788
- drawExpandedRowsOverlay(params, startRowIndex, endRowIndex, rowOffsets);
9802
+ const animation = params.groupHeightAnimation;
9803
+ const splitIndex = animation && animation.progress < 1 ? Array.from(
9804
+ { length: endRowIndex - startRowIndex },
9805
+ (_, offset) => startRowIndex + offset
9806
+ ).find(
9807
+ (index) => (params.rowIndexMap?.[index] ?? index) >= animation.endRowIndex
9808
+ ) ?? endRowIndex : endRowIndex;
9809
+ const drawRange = (start, end) => {
9810
+ drawSegmentRows(
9811
+ params,
9812
+ "center",
9813
+ params.centerColumns,
9814
+ start,
9815
+ end,
9816
+ rowOffsets
9817
+ );
9818
+ drawSegmentRows(params, "left", params.leftColumns, start, end, rowOffsets);
9819
+ drawSegmentRows(
9820
+ params,
9821
+ "right",
9822
+ params.rightColumns,
9823
+ start,
9824
+ end,
9825
+ rowOffsets
9826
+ );
9827
+ drawGroupRowsOverlay(params, start, end, rowOffsets);
9828
+ drawExpandedRowsOverlay(params, start, end, rowOffsets);
9829
+ };
9830
+ drawRange(startRowIndex, splitIndex);
9831
+ if (animation && animation.progress < 1) {
9832
+ drawGroupAnimationMask(params, animation);
9833
+ drawRange(splitIndex, endRowIndex);
9834
+ }
9789
9835
  if (params.dragReorder) {
9790
9836
  drawDragGhostColumn(params);
9791
9837
  }
@@ -10392,6 +10438,15 @@ function drawGroupRowsOverlay(params, startRowIndex, endRowIndex, rowOffsets) {
10392
10438
  if (layout.clipRect.width <= 0) {
10393
10439
  return;
10394
10440
  }
10441
+ const rowSelectorColumn = [
10442
+ ...params.leftColumns,
10443
+ ...params.centerColumns
10444
+ ].find((column) => column.key === ROW_SELECTOR_COLUMN_KEY);
10445
+ const contentLeft = Math.max(
10446
+ layout.clipRect.x,
10447
+ rowSelectorColumn ? rowSelectorColumn.drawX + rowSelectorColumn.width : layout.clipRect.x
10448
+ );
10449
+ const contentRight = layout.clipRect.x + layout.clipRect.width;
10395
10450
  const { ctx } = params;
10396
10451
  ctx.save();
10397
10452
  ctx.beginPath();
@@ -10423,7 +10478,22 @@ function drawGroupRowsOverlay(params, startRowIndex, endRowIndex, rowOffsets) {
10423
10478
  ctx.fillStyle = params.theme.headerBackgroundColor;
10424
10479
  ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
10425
10480
  drawGridRect(ctx, rect, params.theme, params.theme.borderColor);
10426
- const textX = Math.max(rect.x, layout.clipRect.x) + 12 + Math.max(row.depth, 0) * 18;
10481
+ if (contentLeft >= contentRight) continue;
10482
+ const triggerRect = {
10483
+ x: contentLeft + CONTENT_HORIZONTAL_PADDING + Math.max(row.depth, 0) * 18,
10484
+ y: rect.y + Math.max((rect.height - EXPAND_TRIGGER_SIZE) / 2, 0),
10485
+ width: EXPAND_TRIGGER_SIZE,
10486
+ height: EXPAND_TRIGGER_SIZE
10487
+ };
10488
+ paintExpandTrigger({
10489
+ ctx,
10490
+ rect: triggerRect,
10491
+ expanded: row.expanded,
10492
+ animationProgress: params.getGroupAnimationProgress?.(row.rowKey),
10493
+ color: params.theme.headerTextColor,
10494
+ borderColor: params.theme.borderColor
10495
+ });
10496
+ const textX = triggerRect.x + triggerRect.width + EXPAND_TRIGGER_GAP;
10427
10497
  ctx.fillStyle = params.theme.headerTextColor;
10428
10498
  ctx.font = `${params.theme.headerFontWeight} ${params.theme.fontSize}px ${params.theme.fontFamily}`;
10429
10499
  ctx.textAlign = "left";
@@ -10434,9 +10504,73 @@ function drawGroupRowsOverlay(params, startRowIndex, endRowIndex, rowOffsets) {
10434
10504
  rect.y + rect.height / 2,
10435
10505
  Math.max(layout.clipRect.x + layout.clipRect.width - textX - 12, 0)
10436
10506
  );
10507
+ params.descriptors.push({
10508
+ kind: "group-toggle",
10509
+ rect: {
10510
+ x: contentLeft,
10511
+ y: rect.y,
10512
+ width: contentRight - contentLeft,
10513
+ height: rect.height
10514
+ },
10515
+ contentKey: row.rowKey,
10516
+ cursor: "pointer",
10517
+ tooltipText: row.expanded ? "\u6298\u53E0\u5206\u7EC4" : "\u5C55\u5F00\u5206\u7EC4",
10518
+ debugNodeType: "group-toggle"
10519
+ });
10437
10520
  }
10438
10521
  ctx.restore();
10439
10522
  }
10523
+ function drawGroupAnimationMask(params, animation) {
10524
+ const { ctx } = params;
10525
+ const clipRect = resolveExpandedRowsOverlayLayout(params).clipRect;
10526
+ if (clipRect.width <= 0) return;
10527
+ const contentTop = params.bodyTop + animation.startOffset + params.rowHeight - params.scroll.top;
10528
+ const contentBottom = Math.min(
10529
+ contentTop + animation.contentHeight,
10530
+ params.bodyTop + params.bodyHeight
10531
+ );
10532
+ const visibleBottom = contentTop + animation.contentHeight * animation.progress;
10533
+ if (contentBottom > contentTop && visibleBottom < contentBottom) {
10534
+ ctx.save();
10535
+ ctx.beginPath();
10536
+ ctx.rect(
10537
+ clipRect.x,
10538
+ contentTop,
10539
+ clipRect.width,
10540
+ contentBottom - contentTop
10541
+ );
10542
+ ctx.clip();
10543
+ ctx.fillStyle = params.theme.backgroundColor;
10544
+ ctx.globalAlpha = (1 - animation.progress) * 0.35;
10545
+ ctx.fillRect(
10546
+ clipRect.x,
10547
+ contentTop,
10548
+ clipRect.width,
10549
+ contentBottom - contentTop
10550
+ );
10551
+ ctx.globalAlpha = 1;
10552
+ ctx.fillRect(
10553
+ clipRect.x,
10554
+ visibleBottom,
10555
+ clipRect.width,
10556
+ contentBottom - visibleBottom
10557
+ );
10558
+ ctx.restore();
10559
+ params.descriptors.forEach((descriptor) => {
10560
+ const bounds = descriptor.rect;
10561
+ if (bounds.y >= contentBottom || bounds.y + bounds.height <= contentTop || bounds.x >= clipRect.x + clipRect.width || bounds.x + bounds.width <= clipRect.x) {
10562
+ return;
10563
+ }
10564
+ descriptor.rect = {
10565
+ ...bounds,
10566
+ height: Math.max(
10567
+ Math.min(bounds.y + bounds.height, visibleBottom) - bounds.y,
10568
+ 0
10569
+ )
10570
+ };
10571
+ });
10572
+ }
10573
+ }
10440
10574
  function buildSpanConfigMap(rows, columns, rowIndexMap) {
10441
10575
  const spanConfigMap = /* @__PURE__ */ new Map();
10442
10576
  rows.forEach((record, rowIndex) => {
@@ -10805,8 +10939,27 @@ function drawExpandTrigger(params) {
10805
10939
  width: EXPAND_TRIGGER_SIZE,
10806
10940
  height: EXPAND_TRIGGER_SIZE
10807
10941
  };
10808
- const lines = resolveExpandTriggerLines({
10942
+ paintExpandTrigger({
10943
+ ctx,
10944
+ rect: triggerRect,
10945
+ expanded,
10946
+ animationProgress,
10947
+ color,
10948
+ borderColor
10949
+ });
10950
+ descriptors.push({
10951
+ kind: "expand-trigger",
10809
10952
  rect: triggerRect,
10953
+ rowIndex,
10954
+ columnKey,
10955
+ cursor: "pointer"
10956
+ });
10957
+ return triggerRect;
10958
+ }
10959
+ function paintExpandTrigger(params) {
10960
+ const { ctx, rect, expanded, animationProgress, color, borderColor } = params;
10961
+ const lines = resolveExpandTriggerLines({
10962
+ rect,
10810
10963
  progress: typeof animationProgress === "number" ? animationProgress : expanded ? 1 : 0
10811
10964
  });
10812
10965
  ctx.save();
@@ -10814,7 +10967,7 @@ function drawExpandTrigger(params) {
10814
10967
  ctx.strokeStyle = borderColor;
10815
10968
  ctx.lineWidth = 1;
10816
10969
  ctx.beginPath();
10817
- appendRoundedRectPath2(ctx, triggerRect, 2);
10970
+ appendRoundedRectPath2(ctx, rect, 2);
10818
10971
  ctx.fill();
10819
10972
  ctx.stroke();
10820
10973
  ctx.strokeStyle = color;
@@ -10829,14 +10982,6 @@ function drawExpandTrigger(params) {
10829
10982
  }
10830
10983
  ctx.stroke();
10831
10984
  ctx.restore();
10832
- descriptors.push({
10833
- kind: "expand-trigger",
10834
- rect: triggerRect,
10835
- rowIndex,
10836
- columnKey,
10837
- cursor: "pointer"
10838
- });
10839
- return triggerRect;
10840
10985
  }
10841
10986
  function resolveExpandTriggerLines(params) {
10842
10987
  const { rect } = params;
@@ -20313,9 +20458,15 @@ function resolveCollapsedRowRange(params) {
20313
20458
 
20314
20459
  // src/engine/controllers/animation-controller.ts
20315
20460
  var ROW_EXPAND_ANIMATION_DURATION = 240;
20461
+ var GROUPING_REMOVE_HOVER_DURATION = 180;
20316
20462
  var ROW_SORT_ANIMATION_DURATION = 420;
20317
20463
  var ListTableAnimationController = class {
20318
20464
  constructor(options) {
20465
+ __publicField(this, "groupingRemoveAnimations", /* @__PURE__ */ new Map());
20466
+ __publicField(this, "groupingRemoveHoverKey", null);
20467
+ __publicField(this, "groupingRemoveFrameId", null);
20468
+ __publicField(this, "groupAnimations", /* @__PURE__ */ new Map());
20469
+ __publicField(this, "groupAnimationFrameId", null);
20319
20470
  __publicField(this, "pendingSortRowPositions", null);
20320
20471
  __publicField(this, "sortRowsReady", false);
20321
20472
  __publicField(this, "runtime");
@@ -20562,6 +20713,125 @@ var ListTableAnimationController = class {
20562
20713
  }
20563
20714
  return getRowAnimationValue(animation, this.scheduler.now());
20564
20715
  }
20716
+ /** 启动分组子行的显隐动画,折叠完成后再移除子行。 */
20717
+ startGroupAnimation(rowKey, expanded, geometry, onCollapseComplete) {
20718
+ const now2 = this.scheduler.now();
20719
+ const active = this.groupAnimations.get(rowKey);
20720
+ const from = active ? getRowAnimationValue(active, now2) : expanded ? 0 : 1;
20721
+ const to = expanded ? 1 : 0;
20722
+ this.groupAnimations.set(rowKey, {
20723
+ from,
20724
+ to,
20725
+ startTime: now2,
20726
+ duration: ROW_EXPAND_ANIMATION_DURATION,
20727
+ ...geometry,
20728
+ onCollapseComplete
20729
+ });
20730
+ this.ensureGroupAnimationFrame();
20731
+ }
20732
+ getGroupAnimationProgress(rowKey) {
20733
+ const animation = this.groupAnimations.get(rowKey);
20734
+ return animation ? getRowAnimationValue(animation, this.scheduler.now()) : void 0;
20735
+ }
20736
+ getGroupAnimationTarget(rowKey) {
20737
+ return this.groupAnimations.get(rowKey)?.to;
20738
+ }
20739
+ getGroupHeightAnimation() {
20740
+ const first = this.groupAnimations.entries().next().value;
20741
+ if (!first) return void 0;
20742
+ const [rowKey, animation] = first;
20743
+ return {
20744
+ rowKey,
20745
+ startOffset: animation.startOffset,
20746
+ contentHeight: animation.contentHeight,
20747
+ endRowIndex: animation.endRowIndex,
20748
+ progress: getRowAnimationValue(animation, this.scheduler.now())
20749
+ };
20750
+ }
20751
+ /** 根据分组栏移除图标的悬停位置启动或反向播放旋转动画。 */
20752
+ reconcileGroupingRemoveHover(hover) {
20753
+ const nextKey = hover.area === "grouping-remove" ? hover.columnKey : null;
20754
+ if (nextKey === this.groupingRemoveHoverKey) return;
20755
+ const now2 = this.scheduler.now();
20756
+ const previousKey = this.groupingRemoveHoverKey;
20757
+ if (previousKey) {
20758
+ const active = this.groupingRemoveAnimations.get(previousKey);
20759
+ this.groupingRemoveAnimations.set(previousKey, {
20760
+ from: active ? getRowAnimationValue(active, now2) : 1,
20761
+ to: 0,
20762
+ startTime: now2,
20763
+ duration: GROUPING_REMOVE_HOVER_DURATION
20764
+ });
20765
+ }
20766
+ this.groupingRemoveHoverKey = nextKey;
20767
+ if (nextKey) {
20768
+ const active = this.groupingRemoveAnimations.get(nextKey);
20769
+ this.groupingRemoveAnimations.set(nextKey, {
20770
+ from: active ? getRowAnimationValue(active, now2) : 0,
20771
+ to: 1,
20772
+ startTime: now2,
20773
+ duration: GROUPING_REMOVE_HOVER_DURATION
20774
+ });
20775
+ }
20776
+ this.ensureGroupingRemoveFrame();
20777
+ }
20778
+ getGroupingRemoveAnimationProgress(columnKey) {
20779
+ const animation = this.groupingRemoveAnimations.get(columnKey);
20780
+ return animation ? getRowAnimationValue(animation, this.scheduler.now()) : columnKey === this.groupingRemoveHoverKey ? 1 : 0;
20781
+ }
20782
+ ensureGroupingRemoveFrame() {
20783
+ if (this.groupingRemoveAnimations.size === 0 || this.groupingRemoveFrameId != null)
20784
+ return;
20785
+ this.groupingRemoveFrameId = this.scheduler.requestAnimationFrame(() => {
20786
+ this.groupingRemoveFrameId = null;
20787
+ const now2 = this.scheduler.now();
20788
+ for (const [key, animation] of this.groupingRemoveAnimations) {
20789
+ if (now2 - animation.startTime >= animation.duration) {
20790
+ this.groupingRemoveAnimations.delete(key);
20791
+ }
20792
+ }
20793
+ this.requestRender();
20794
+ this.ensureGroupingRemoveFrame();
20795
+ });
20796
+ }
20797
+ stopGroupingRemoveAnimation() {
20798
+ if (this.groupingRemoveFrameId != null) {
20799
+ this.scheduler.cancelAnimationFrame(this.groupingRemoveFrameId);
20800
+ this.groupingRemoveFrameId = null;
20801
+ }
20802
+ this.groupingRemoveAnimations.clear();
20803
+ this.groupingRemoveHoverKey = null;
20804
+ }
20805
+ ensureGroupAnimationFrame() {
20806
+ if (this.groupAnimations.size === 0 || this.groupAnimationFrameId != null) {
20807
+ return;
20808
+ }
20809
+ this.groupAnimationFrameId = this.scheduler.requestAnimationFrame(() => {
20810
+ this.groupAnimationFrameId = null;
20811
+ const now2 = this.scheduler.now();
20812
+ for (const [rowKey, animation] of this.groupAnimations) {
20813
+ if (now2 - animation.startTime < animation.duration) continue;
20814
+ this.groupAnimations.delete(rowKey);
20815
+ if (animation.to === 0) animation.onCollapseComplete?.();
20816
+ }
20817
+ this.requestRender();
20818
+ this.ensureGroupAnimationFrame();
20819
+ });
20820
+ }
20821
+ stopGroupAnimations() {
20822
+ if (this.groupAnimationFrameId != null) {
20823
+ this.scheduler.cancelAnimationFrame(this.groupAnimationFrameId);
20824
+ this.groupAnimationFrameId = null;
20825
+ }
20826
+ this.groupAnimations.clear();
20827
+ }
20828
+ finishGroupAnimations() {
20829
+ const pending = [...this.groupAnimations.values()];
20830
+ this.stopGroupAnimations();
20831
+ pending.forEach((animation) => {
20832
+ if (animation.to === 0) animation.onCollapseComplete?.();
20833
+ });
20834
+ }
20565
20835
  getCollapseRowOffset(rowKey) {
20566
20836
  const key = String(rowKey);
20567
20837
  const now2 = this.scheduler.now();
@@ -21068,6 +21338,8 @@ var ListTableAnimationController = class {
21068
21338
  this.sortRowsReady = false;
21069
21339
  }
21070
21340
  destroy() {
21341
+ this.stopGroupingRemoveAnimation();
21342
+ this.stopGroupAnimations();
21071
21343
  this.stopScrollbarOpacityAnimation();
21072
21344
  this.stopSwapAnimation();
21073
21345
  this.scrollAnimationController.destroy();
@@ -21083,6 +21355,8 @@ var ListTableAnimationController = class {
21083
21355
  * 停止所有动画循环(销毁前调用)。
21084
21356
  */
21085
21357
  stopAll() {
21358
+ this.stopGroupingRemoveAnimation();
21359
+ this.stopGroupAnimations();
21086
21360
  this.stopCarouselScroll();
21087
21361
  this.stopScrollToAnimation();
21088
21362
  this.stopWheelScrollSmoothing();
@@ -22179,6 +22453,7 @@ function openCellEditingSession(params) {
22179
22453
  fontFamily: theme.fontFamily,
22180
22454
  textColor: theme.textColor,
22181
22455
  cellColor: column.cellStyle?.color,
22456
+ textAlign: column.cellStyle?.textAlign ?? column.align,
22182
22457
  paddingInline,
22183
22458
  paddingBlock,
22184
22459
  contentZoom: zoom
@@ -22819,7 +23094,7 @@ var ListTableEditingController = class {
22819
23094
  await this.validateCellTargets(rowIndex, columnKey);
22820
23095
  }
22821
23096
  }
22822
- const values = this.options.getDisplayData();
23097
+ const values = this.options.getAllDisplayData();
22823
23098
  const leafColumns = this.options.getLeafColumns();
22824
23099
  const tableOptions = this.options.getOptions();
22825
23100
  const taskId = ++this.validationTaskId;
@@ -23562,7 +23837,10 @@ var groupedRowsCache = /* @__PURE__ */ new WeakMap();
23562
23837
  function flattenGroupedRows(params) {
23563
23838
  const startedAt = resolvePerformanceNow2();
23564
23839
  const cached = groupedRowsCache.get(params.rows);
23565
- if (cached && areSameStringArray(cached.groupColumnKeys, params.groupColumnKeys) && areSameKeyArray(cached.expandedRowKeys, params.expandedRowKeys) && cached.rowKey === params.options.rowKey && cached.expandable === params.options.expandable) {
23840
+ if (cached && areSameStringArray(cached.groupColumnKeys, params.groupColumnKeys) && areSameKeyArray(cached.expandedRowKeys, params.expandedRowKeys) && areSameStringArray(
23841
+ cached.collapsedGroupKeys,
23842
+ params.collapsedGroupKeys ?? []
23843
+ ) && cached.rowKey === params.options.rowKey && cached.expandable === params.options.expandable) {
23566
23844
  return cached.visibleRows;
23567
23845
  }
23568
23846
  const groupColumns = params.groupColumnKeys.map((key) => params.leafColumns.find((column) => column.key === key)).filter(
@@ -23584,6 +23862,7 @@ function flattenGroupedRows(params) {
23584
23862
  groupedRowsCache.set(params.rows, {
23585
23863
  groupColumnKeys: [...params.groupColumnKeys],
23586
23864
  expandedRowKeys: [...params.expandedRowKeys],
23865
+ collapsedGroupKeys: [...params.collapsedGroupKeys ?? []],
23587
23866
  rowKey: params.options.rowKey,
23588
23867
  expandable: params.options.expandable,
23589
23868
  visibleRows: visibleRows2
@@ -23591,6 +23870,7 @@ function flattenGroupedRows(params) {
23591
23870
  return visibleRows2;
23592
23871
  }
23593
23872
  const visibleRows = [];
23873
+ const collapsedGroupKeys = new Set(params.collapsedGroupKeys);
23594
23874
  let dataRowOffset = 0;
23595
23875
  let hasExpandedRows = false;
23596
23876
  let groupedRowCount = 0;
@@ -23647,20 +23927,32 @@ function flattenGroupedRows(params) {
23647
23927
  buckets.forEach((bucket) => {
23648
23928
  const serializedValue = serializeGroupValue(bucket.value);
23649
23929
  const nextKeyPath = [...keyPath, `${column.key}:${serializedValue}`];
23930
+ const rowKey = `__list_table_group__${nextKeyPath.join("/")}`;
23931
+ const expanded = !collapsedGroupKeys.has(rowKey);
23650
23932
  visibleRows.push({
23651
23933
  kind: "group",
23652
23934
  record: bucket.rows[0],
23653
- rowKey: `__list_table_group__${nextKeyPath.join("/")}`,
23935
+ rowKey,
23654
23936
  groupColumnKey: column.key,
23655
23937
  columnTitle: column.title,
23656
23938
  value: bucket.value,
23657
23939
  valueText: formatGroupValue(bucket.value),
23658
23940
  count: bucket.rows.length,
23659
23941
  depth,
23942
+ expanded,
23660
23943
  sourceDataRowIndex: dataRowOffset
23661
23944
  });
23662
23945
  groupedRowCount += 1;
23663
- visit(bucket.rows, depth + 1, nextKeyPath);
23946
+ if (expanded) visit(bucket.rows, depth + 1, nextKeyPath);
23947
+ else if (!params.options.expandable || params.expandedRowKeys.length === 0) {
23948
+ dataRowOffset += bucket.rows.length;
23949
+ } else {
23950
+ dataRowOffset += flattenExpandableRows({
23951
+ options: params.options,
23952
+ rows: bucket.rows,
23953
+ expandedRowKeys: params.expandedRowKeys
23954
+ }).filter((row) => row.kind === "data").length;
23955
+ }
23664
23956
  });
23665
23957
  };
23666
23958
  visit(params.rows, 0, []);
@@ -23670,6 +23962,7 @@ function flattenGroupedRows(params) {
23670
23962
  groupedRowsCache.set(params.rows, {
23671
23963
  groupColumnKeys: [...params.groupColumnKeys],
23672
23964
  expandedRowKeys: [...params.expandedRowKeys],
23965
+ collapsedGroupKeys: [...params.collapsedGroupKeys ?? []],
23673
23966
  rowKey: params.options.rowKey,
23674
23967
  expandable: params.options.expandable,
23675
23968
  visibleRows
@@ -24011,9 +24304,14 @@ function areSameGroupColumnAccessors(left, right) {
24011
24304
  function buildListTableGroupVisibilityPlan(params) {
24012
24305
  const nodeVisibility = /* @__PURE__ */ new WeakMap();
24013
24306
  const collapsedKeySet = new Set(params.collapsedRowKeys);
24307
+ const collapsedGroupKeySet = new Set(params.collapsedGroupKeys);
24014
24308
  const excludedKeySet = new Set(params.excludedRowKeys);
24015
24309
  const collapsedDataRowIndexes = [];
24016
24310
  const visit = (node, isRoot = false) => {
24311
+ if (!isRoot && collapsedGroupKeySet.has(node.nodeKey)) {
24312
+ nodeVisibility.set(node, { visibleRowCount: 1 });
24313
+ return 1;
24314
+ }
24017
24315
  if (node.sourceIndexes) {
24018
24316
  const hiddenDataIndexes = [];
24019
24317
  node.sourceIndexes.forEach((sourceIndex, index) => {
@@ -24048,6 +24346,7 @@ function buildListTableGroupVisibilityPlan(params) {
24048
24346
  index: params.index,
24049
24347
  rowKey: params.options.rowKey,
24050
24348
  collapsedRowKeys: [...params.collapsedRowKeys],
24349
+ collapsedGroupKeys: [...params.collapsedGroupKeys ?? []],
24051
24350
  excludedRowKeys: [...params.excludedRowKeys ?? []],
24052
24351
  nodeVisibility,
24053
24352
  visibleRowCount,
@@ -24165,58 +24464,117 @@ function resolveListTableGroupVisibleRowWindow(params) {
24165
24464
  const baseRowCount = params.visibilityPlan?.visibleRowCount ?? params.index.visibleRowCount;
24166
24465
  const totalRowCount = params.expandedRowPlan?.totalRowCount ?? baseRowCount;
24167
24466
  const overscan = params.overscan ?? 3;
24168
- const start = params.expandedRowPlan?.entries.length ? Math.max(
24169
- resolveBaseRowIndexAtOffset(
24170
- params.expandedRowPlan,
24171
- params.scrollTop,
24172
- params.rowHeight
24173
- ) - overscan,
24174
- 0
24175
- ) : Math.max(Math.floor(params.scrollTop / params.rowHeight) - overscan, 0);
24176
- const end = params.expandedRowPlan?.entries.length ? Math.min(
24177
- resolveBaseRowIndexAtOffset(
24178
- params.expandedRowPlan,
24179
- params.scrollTop + params.bodyHeight,
24180
- params.rowHeight
24181
- ) + overscan + 2,
24182
- baseRowCount
24183
- ) : Math.min(
24184
- Math.ceil((params.scrollTop + params.bodyHeight) / params.rowHeight) + overscan + 1,
24467
+ const animation = params.heightAnimation;
24468
+ const removedHeight = animation ? animation.contentHeight * (1 - animation.progress) : 0;
24469
+ const fullEndOffset = animation ? animation.startOffset + params.rowHeight + animation.contentHeight : 0;
24470
+ const visualEndOffset = fullEndOffset - removedHeight;
24471
+ const viewportEnd = params.scrollTop + params.bodyHeight;
24472
+ const pixelRanges = animation && removedHeight > 1e-3 ? [
24473
+ ...params.scrollTop < visualEndOffset ? [
24474
+ [
24475
+ params.scrollTop,
24476
+ Math.min(viewportEnd, visualEndOffset)
24477
+ ]
24478
+ ] : [],
24479
+ ...viewportEnd > visualEndOffset ? [
24480
+ [
24481
+ Math.max(params.scrollTop, visualEndOffset) + removedHeight,
24482
+ viewportEnd + removedHeight
24483
+ ]
24484
+ ] : []
24485
+ ] : [[params.scrollTop, viewportEnd]];
24486
+ const rowRanges = animation && removedHeight > 1e-3 ? pixelRanges.map(([from, to]) => ({
24487
+ start: Math.max(
24488
+ resolveBaseRowIndexAtOffset(
24489
+ params.expandedRowPlan,
24490
+ from,
24491
+ params.rowHeight
24492
+ ) - overscan,
24493
+ 0
24494
+ ),
24495
+ end: Math.min(
24496
+ resolveBaseRowIndexAtOffset(
24497
+ params.expandedRowPlan,
24498
+ to,
24499
+ params.rowHeight
24500
+ ) + overscan + 2,
24501
+ baseRowCount
24502
+ )
24503
+ })) : [
24504
+ {
24505
+ start: params.expandedRowPlan?.entries.length ? Math.max(
24506
+ resolveBaseRowIndexAtOffset(
24507
+ params.expandedRowPlan,
24508
+ params.scrollTop,
24509
+ params.rowHeight
24510
+ ) - overscan,
24511
+ 0
24512
+ ) : Math.max(
24513
+ Math.floor(params.scrollTop / params.rowHeight) - overscan,
24514
+ 0
24515
+ ),
24516
+ end: params.expandedRowPlan?.entries.length ? Math.min(
24517
+ resolveBaseRowIndexAtOffset(
24518
+ params.expandedRowPlan,
24519
+ viewportEnd,
24520
+ params.rowHeight
24521
+ ) + overscan + 2,
24522
+ baseRowCount
24523
+ ) : Math.min(
24524
+ Math.ceil(viewportEnd / params.rowHeight) + overscan + 1,
24525
+ baseRowCount
24526
+ )
24527
+ }
24528
+ ];
24529
+ const start = Math.min(
24530
+ ...rowRanges.map((range) => range.start),
24185
24531
  baseRowCount
24186
24532
  );
24533
+ const end = Math.max(...rowRanges.map((range) => range.end), 0);
24187
24534
  const rows = [];
24188
24535
  const rowIndexMap = [];
24189
24536
  const rowOffsetMap = [];
24190
- visitNodeChildren({
24191
- parent: params.index.root,
24192
- parentStart: 0,
24193
- sourceRows: params.index.sourceRows,
24194
- options: params.options,
24195
- start,
24196
- end,
24197
- visibilityPlan: params.visibilityPlan,
24198
- expandedRowPlan: params.expandedRowPlan,
24199
- push: (row, baseRowIndex) => {
24200
- rows.push(row);
24201
- const expanded = row.kind === "expanded";
24202
- rowIndexMap.push(
24203
- resolveRenderedRowIndex(params.expandedRowPlan, baseRowIndex, expanded)
24204
- );
24205
- rowOffsetMap.push(
24206
- resolveBaseRowOffset(
24537
+ const seen = /* @__PURE__ */ new Set();
24538
+ rowRanges.forEach(
24539
+ (range) => visitNodeChildren({
24540
+ parent: params.index.root,
24541
+ parentStart: 0,
24542
+ sourceRows: params.index.sourceRows,
24543
+ options: params.options,
24544
+ start: range.start,
24545
+ end: range.end,
24546
+ visibilityPlan: params.visibilityPlan,
24547
+ expandedRowPlan: params.expandedRowPlan,
24548
+ push: (row, baseRowIndex) => {
24549
+ const key = `${baseRowIndex}:${row.kind}`;
24550
+ if (seen.has(key)) return;
24551
+ seen.add(key);
24552
+ rows.push(row);
24553
+ const expanded = row.kind === "expanded";
24554
+ rowIndexMap.push(
24555
+ resolveRenderedRowIndex(
24556
+ params.expandedRowPlan,
24557
+ baseRowIndex,
24558
+ expanded
24559
+ )
24560
+ );
24561
+ const baseOffset = resolveBaseRowOffset(
24207
24562
  params.expandedRowPlan,
24208
24563
  baseRowIndex,
24209
24564
  params.rowHeight
24210
- ) + (expanded ? params.rowHeight : 0)
24211
- );
24212
- }
24213
- });
24565
+ ) + (expanded ? params.rowHeight : 0);
24566
+ rowOffsetMap.push(
24567
+ baseOffset - (animation && baseOffset >= fullEndOffset ? removedHeight : 0)
24568
+ );
24569
+ }
24570
+ })
24571
+ );
24214
24572
  return {
24215
24573
  rows,
24216
24574
  start,
24217
24575
  end,
24218
24576
  totalRowCount,
24219
- totalBodyHeight: params.expandedRowPlan?.totalBodyHeight ?? totalRowCount * params.rowHeight,
24577
+ totalBodyHeight: (params.expandedRowPlan?.totalBodyHeight ?? totalRowCount * params.rowHeight) - removedHeight,
24220
24578
  dataRowCount: params.index.dataRowCount,
24221
24579
  rowIndexMap,
24222
24580
  rowOffsetMap
@@ -24257,11 +24615,15 @@ function visitNodeChildren(params) {
24257
24615
  valueText: node.valueText,
24258
24616
  count: node.count,
24259
24617
  depth: node.depth,
24618
+ expanded: !params.visibilityPlan?.collapsedGroupKeys.includes(
24619
+ node.nodeKey
24620
+ ),
24260
24621
  sourceDataRowIndex: node.firstDataRowIndex
24261
24622
  },
24262
24623
  nodeStart
24263
24624
  );
24264
24625
  }
24626
+ if (nodeRowCount === 1) continue;
24265
24627
  if (node.children) {
24266
24628
  visitNodeChildren({ ...params, parent: node, parentStart: nodeStart });
24267
24629
  continue;
@@ -24928,6 +25290,7 @@ function buildListTableGroupExpandedRowPlan(params) {
24928
25290
  }
24929
25291
  const visit = (nodes, parent, parentStart) => {
24930
25292
  nodes.forEach((node, nodeIndex) => {
25293
+ if (params.visibilityPlan?.collapsedGroupKeys.includes(node.nodeKey)) return;
24931
25294
  const nodeStart = parentStart + (getGroupNodeChildRowOffsets(params.visibilityPlan, parent)[nodeIndex] ?? 0);
24932
25295
  if (node.children) {
24933
25296
  visit(node.children, node, nodeStart);
@@ -25145,6 +25508,7 @@ function buildListTableRenderSnapshot(params) {
25145
25508
  });
25146
25509
  const groupColumnKeys = params.groupColumnKeys ?? [];
25147
25510
  const collapsedRowKeys = params.collapsedRowKeys ?? [];
25511
+ const collapsedGroupKeys = params.collapsedGroupKeys ?? [];
25148
25512
  const expandedRowKeys = params.expandedRowKeys ?? expandableState.expandedRowKeys;
25149
25513
  const canUsePlainRowWindow = groupColumnKeys.length === 0 && expandedRowKeys.length === 0 && collapsedRowKeys.length === 0 && frozenRows.topRowKeys.length === 0 && frozenRows.bottomRowKeys.length === 0;
25150
25514
  const plainRowWindow = canUsePlainRowWindow ? resolvePlainVisibleRowWindow({
@@ -25183,6 +25547,7 @@ function buildListTableRenderSnapshot(params) {
25183
25547
  index: groupIndex,
25184
25548
  options,
25185
25549
  collapsedRowKeys,
25550
+ collapsedGroupKeys,
25186
25551
  excludedRowKeys: [
25187
25552
  ...frozenRows.topRowKeys,
25188
25553
  ...frozenRows.bottomRowKeys
@@ -25247,16 +25612,27 @@ function buildListTableRenderSnapshot(params) {
25247
25612
  rows: [...indexedFrozenRows.top, ...indexedFrozenRows.bottom],
25248
25613
  rowHeight
25249
25614
  }) : 0;
25615
+ const groupWindowBodyHeight = Math.max(
25616
+ initialBodyLayout.bodyAreaHeight - indexedFrozenHeight,
25617
+ 0
25618
+ );
25619
+ const groupWindowTotalHeight = groupExpandedRowPlan?.totalBodyHeight ?? (groupVisibilityPlan?.visibleRowCount ?? groupIndex?.visibleRowCount ?? 0) * rowHeight;
25620
+ const groupAnimationRemovedHeight = params.groupHeightAnimation ? params.groupHeightAnimation.contentHeight * (1 - params.groupHeightAnimation.progress) : 0;
25621
+ const groupWindowScrollTop = Math.min(
25622
+ Math.max(scroll.top, 0),
25623
+ Math.max(
25624
+ groupWindowTotalHeight - groupAnimationRemovedHeight - groupWindowBodyHeight,
25625
+ 0
25626
+ )
25627
+ );
25250
25628
  const groupVisibleWindow = canMaterializeGroupIndex ? resolveListTableGroupVisibleRowWindow({
25251
25629
  index: groupIndex,
25252
25630
  options,
25253
- scrollTop: scroll.top,
25254
- bodyHeight: Math.max(
25255
- initialBodyLayout.bodyAreaHeight - indexedFrozenHeight,
25256
- 0
25257
- ),
25631
+ scrollTop: groupWindowScrollTop,
25632
+ bodyHeight: groupWindowBodyHeight,
25258
25633
  rowHeight,
25259
25634
  visibilityPlan: groupVisibilityPlan,
25635
+ heightAnimation: params.groupHeightAnimation,
25260
25636
  expandedRowPlan: hasExpandedDetailRows ? groupExpandedRowPlan : void 0
25261
25637
  }) : void 0;
25262
25638
  const isGroupIndexBuilding = canUseGroupIndex && params.useAsyncGroupIndex === true && !groupIndex && expandedRowKeys.length === 0;
@@ -25265,7 +25641,8 @@ function buildListTableRenderSnapshot(params) {
25265
25641
  rows: queryRows.displayRows,
25266
25642
  leafColumns: sourceLeafColumns,
25267
25643
  groupColumnKeys,
25268
- expandedRowKeys
25644
+ expandedRowKeys,
25645
+ collapsedGroupKeys
25269
25646
  }).map(measureExpandedRow);
25270
25647
  if (autoRowHeight) {
25271
25648
  visibleRows.forEach((row) => {
@@ -25323,16 +25700,25 @@ function buildListTableRenderSnapshot(params) {
25323
25700
  bottomFrozenRowCount: indexedFrozenRows.bottom.length,
25324
25701
  scrollRowCount: groupVisibleWindow.totalRowCount
25325
25702
  })
25326
- } : resolveFrozenBodyRenderState({
25327
- visibleRows: filteredVisibleRows,
25328
- frozenState: frozenRows,
25329
- getRowKey: (row) => row.kind === "data" ? row.rowKey : null,
25330
- height: contentHeight,
25703
+ } : resolveGroupedFallbackAnimation(
25704
+ resolveFrozenBodyRenderState({
25705
+ visibleRows: filteredVisibleRows,
25706
+ frozenState: frozenRows,
25707
+ getRowKey: (row) => row.kind === "data" ? row.rowKey : null,
25708
+ height: contentHeight,
25709
+ headerHeight,
25710
+ summaryRowHeight,
25711
+ hasSummary,
25712
+ rowHeight
25713
+ }),
25714
+ params.groupHeightAnimation,
25715
+ rowHeight,
25716
+ contentHeight,
25331
25717
  headerHeight,
25332
25718
  summaryRowHeight,
25333
25719
  hasSummary,
25334
- rowHeight
25335
- });
25720
+ scroll.top
25721
+ );
25336
25722
  let bodyState = resolveCurrentBodyState();
25337
25723
  if (plainRowWindow) {
25338
25724
  bodyState.frozenRows.scroll.windowed = true;
@@ -25454,6 +25840,7 @@ function buildListTableRenderSnapshot(params) {
25454
25840
  groupVisibleWindow,
25455
25841
  groupVisibilityPlan,
25456
25842
  groupExpandedRowPlan,
25843
+ groupHeightAnimation: params.groupHeightAnimation,
25457
25844
  dataRowCount,
25458
25845
  collapsedRowCount,
25459
25846
  collapsedDataRowIndexes,
@@ -25536,9 +25923,76 @@ function resolveGroupIndex(params) {
25536
25923
  }
25537
25924
  return void 0;
25538
25925
  }
25926
+ function resolveGroupedFallbackAnimation(state, animation, rowHeight, height, headerHeight, summaryRowHeight, hasSummary, requestedScrollTop) {
25927
+ if (!animation || animation.contentHeight <= 0) return state;
25928
+ const section = state.frozenRows.scroll;
25929
+ const sourceRows = section.rows;
25930
+ const offsets = getVisibleRowOffsets(sourceRows, rowHeight);
25931
+ const getOffset = (index) => offsets?.[index] ?? index * rowHeight;
25932
+ const findIndex = (offset) => offsets ? resolveVisibleRowIndexAtOffset(offsets, offset) : Math.max(Math.floor(offset / rowHeight), 0);
25933
+ const removedHeight = animation.contentHeight * (1 - animation.progress);
25934
+ const fullEnd = animation.startOffset + rowHeight + animation.contentHeight;
25935
+ const visualEnd = fullEnd - removedHeight;
25936
+ const scrollTop = Math.min(
25937
+ Math.max(
25938
+ 0,
25939
+ state.bodyLayout.totalBodyHeight - removedHeight - state.bodyLayout.scrollBodyHeight
25940
+ ),
25941
+ Math.max(requestedScrollTop, 0)
25942
+ );
25943
+ const viewportTop = scrollTop;
25944
+ const viewportBottom = viewportTop + state.bodyLayout.scrollBodyHeight;
25945
+ const ranges = [
25946
+ ...viewportTop < visualEnd ? [[viewportTop, Math.min(viewportBottom, visualEnd)]] : [],
25947
+ ...viewportBottom > visualEnd ? [
25948
+ [
25949
+ Math.max(viewportTop, visualEnd) + removedHeight,
25950
+ viewportBottom + removedHeight
25951
+ ]
25952
+ ] : []
25953
+ ];
25954
+ const rows = [];
25955
+ const rowIndexMap = [];
25956
+ const rowOffsetMap = [];
25957
+ const seen = /* @__PURE__ */ new Set();
25958
+ ranges.forEach(([from, to]) => {
25959
+ const start = Math.max(findIndex(from) - 3, 0);
25960
+ const end = Math.min(findIndex(to) + 5, sourceRows.length);
25961
+ for (let index = start; index < end; index += 1) {
25962
+ if (seen.has(index)) continue;
25963
+ seen.add(index);
25964
+ rows.push(sourceRows[index]);
25965
+ rowIndexMap.push(section.rowIndexMap?.[index] ?? index);
25966
+ const baseOffset = getOffset(index);
25967
+ rowOffsetMap.push(
25968
+ baseOffset - (baseOffset >= fullEnd ? removedHeight : 0)
25969
+ );
25970
+ }
25971
+ });
25972
+ return {
25973
+ ...state,
25974
+ frozenRows: {
25975
+ ...state.frozenRows,
25976
+ scroll: { rows, rowIndexMap, rowOffsetMap, windowed: true }
25977
+ },
25978
+ bodyLayout: resolveBodyLayout({
25979
+ height,
25980
+ headerHeight,
25981
+ summaryRowHeight,
25982
+ hasSummary,
25983
+ rowHeight,
25984
+ topFrozenHeight: state.bodyLayout.topFrozenHeight,
25985
+ bottomFrozenHeight: state.bodyLayout.bottomFrozenHeight,
25986
+ totalBodyHeight: state.bodyLayout.totalBodyHeight - removedHeight,
25987
+ topFrozenRowCount: state.frozenRows.top.rows.length,
25988
+ bottomFrozenRowCount: state.frozenRows.bottom.rows.length,
25989
+ scrollRowCount: sourceRows.length
25990
+ })
25991
+ };
25992
+ }
25539
25993
  function resolveGroupVisibilityPlan(params) {
25540
25994
  const cached = params.cache?.groupVisibilityPlan;
25541
- if (cached?.index === params.index && cached.rowKey === params.options.rowKey && areSameKeyArrays(cached.collapsedRowKeys, params.collapsedRowKeys) && areSameKeyArrays(cached.excludedRowKeys, params.excludedRowKeys ?? [])) {
25995
+ if (cached?.index === params.index && cached.rowKey === params.options.rowKey && areSameKeyArrays(cached.collapsedRowKeys, params.collapsedRowKeys) && areSameStringArrays(cached.collapsedGroupKeys, params.collapsedGroupKeys) && areSameKeyArrays(cached.excludedRowKeys, params.excludedRowKeys ?? [])) {
25542
25996
  return cached;
25543
25997
  }
25544
25998
  const plan = buildListTableGroupVisibilityPlan(params);
@@ -25718,6 +26172,8 @@ function createRenderCacheInputs(params) {
25718
26172
  selectedRowKeys: params.selectedRowKeys,
25719
26173
  expandedRowKeys: params.expandedRowKeys,
25720
26174
  collapsedRowKeys: params.collapsedRowKeys,
26175
+ collapsedGroupKeys: params.collapsedGroupKeys,
26176
+ groupHeightAnimation: params.groupHeightAnimation,
25721
26177
  query: params.query,
25722
26178
  frozenRows: params.frozenRows,
25723
26179
  draggingResize: params.draggingResize,
@@ -25732,7 +26188,7 @@ function isSameRenderCacheInputs(previous, next) {
25732
26188
  if (!previous || next.swapAnimation) {
25733
26189
  return false;
25734
26190
  }
25735
- return previous.options === next.options && previous.jsonCellLayoutRevision === getJsonCellLayoutRevision() && previous.summaryRowHeight === next.options.summaryRowHeight && previous.columnsSignature === resolveColumnsSignature(next.options) && previous.theme === next.theme && previous.width === next.width && previous.height === next.height && previous.selectedRowKeys === next.selectedRowKeys && previous.expandedRowKeys === next.expandedRowKeys && previous.collapsedRowKeys === next.collapsedRowKeys && previous.query.sortState === next.query.sortState && previous.query.filterState === next.query.filterState && previous.query.pagination === next.query.pagination && previous.frozenRows === next.frozenRows && previous.draggingResize === next.draggingResize && previous.draggingResizeColumnKey === next.draggingResizeColumnKey && previous.baseRowsOverride === next.baseRowsOverride && previous.displayRowsOverride === next.displayRowsOverride && previous.groupBarVisible === next.groupBarVisible && areSameStringArrays(previous.groupColumnKeys, next.groupColumnKeys);
26191
+ return previous.options === next.options && previous.jsonCellLayoutRevision === getJsonCellLayoutRevision() && previous.summaryRowHeight === next.options.summaryRowHeight && previous.columnsSignature === resolveColumnsSignature(next.options) && previous.theme === next.theme && previous.width === next.width && previous.height === next.height && previous.selectedRowKeys === next.selectedRowKeys && previous.expandedRowKeys === next.expandedRowKeys && previous.collapsedRowKeys === next.collapsedRowKeys && previous.collapsedGroupKeys === next.collapsedGroupKeys && previous.groupHeightAnimation === next.groupHeightAnimation && previous.query.sortState === next.query.sortState && previous.query.filterState === next.query.filterState && previous.query.pagination === next.query.pagination && previous.frozenRows === next.frozenRows && previous.draggingResize === next.draggingResize && previous.draggingResizeColumnKey === next.draggingResizeColumnKey && previous.baseRowsOverride === next.baseRowsOverride && previous.displayRowsOverride === next.displayRowsOverride && previous.groupBarVisible === next.groupBarVisible && areSameStringArrays(previous.groupColumnKeys, next.groupColumnKeys);
25736
26192
  }
25737
26193
  function resolveRenderCacheMissReason(previous, next) {
25738
26194
  if (!previous) return "empty";
@@ -25757,6 +26213,12 @@ function resolveRenderCacheMissReason(previous, next) {
25757
26213
  if (previous.collapsedRowKeys !== next.collapsedRowKeys) {
25758
26214
  return "collapsed-rows";
25759
26215
  }
26216
+ if (previous.collapsedGroupKeys !== next.collapsedGroupKeys) {
26217
+ return "collapsed-groups";
26218
+ }
26219
+ if (previous.groupHeightAnimation !== next.groupHeightAnimation) {
26220
+ return "group-animation";
26221
+ }
25760
26222
  if (previous.query.sortState !== next.query.sortState) return "sort";
25761
26223
  if (previous.query.filterState !== next.query.filterState) return "filter";
25762
26224
  if (previous.query.pagination !== next.query.pagination) return "pagination";
@@ -26365,6 +26827,8 @@ function drawListTableBodySections(params) {
26365
26827
  descriptors: params.descriptors,
26366
26828
  collapseConfig: params.collapseConfig,
26367
26829
  expandableConfig: params.expandableConfig,
26830
+ getGroupAnimationProgress: params.getGroupAnimationProgress,
26831
+ groupHeightAnimation: params.groupHeightAnimation,
26368
26832
  getCollapseRowOffset: params.getCollapseRowOffset,
26369
26833
  getCollapseCellHeight: params.getCollapseCellHeight,
26370
26834
  dragReorder: params.dragReorder,
@@ -26452,6 +26916,8 @@ function drawBodySection(params) {
26452
26916
  descriptors: params.descriptors,
26453
26917
  collapseConfig: params.collapseConfig,
26454
26918
  expandableConfig: params.expandableConfig,
26919
+ getGroupAnimationProgress: params.getGroupAnimationProgress,
26920
+ groupHeightAnimation: params.frozen ? void 0 : params.groupHeightAnimation,
26455
26921
  getCollapseRowOffset: params.getCollapseRowOffset,
26456
26922
  getCollapseCellHeight: params.getCollapseCellHeight,
26457
26923
  dragReorder: params.dragReorder,
@@ -27194,6 +27660,8 @@ function executeListTableRenderPipeline(params) {
27194
27660
  getControlAnimationProgress,
27195
27661
  getNestedTableHighlight,
27196
27662
  getExpandAnimationProgress,
27663
+ getGroupAnimationProgress,
27664
+ getGroupingRemoveAnimationProgress,
27197
27665
  getCollapseCellHeight,
27198
27666
  getValidationMessage,
27199
27667
  requestRender,
@@ -27226,7 +27694,8 @@ function executeListTableRenderPipeline(params) {
27226
27694
  columns: snapshot.groupingColumns,
27227
27695
  theme,
27228
27696
  descriptors,
27229
- hover
27697
+ hover,
27698
+ getGroupingRemoveAnimationProgress
27230
27699
  });
27231
27700
  if (snapshot.displayRows.length === 0) {
27232
27701
  renderer.drawEmpty(
@@ -27281,6 +27750,8 @@ function executeListTableRenderPipeline(params) {
27281
27750
  inlineColumnKey: inlineExpandColumnKey,
27282
27751
  getExpandAnimationProgress
27283
27752
  } : void 0,
27753
+ getGroupAnimationProgress,
27754
+ groupHeightAnimation: snapshot.groupHeightAnimation,
27284
27755
  dragReorder: dragReorderState,
27285
27756
  getControlAnimationProgress,
27286
27757
  getNestedTableHighlight,
@@ -27456,7 +27927,16 @@ function executeListTableRenderPipeline(params) {
27456
27927
  }
27457
27928
  function drawGroupingBar(params) {
27458
27929
  if (params.height <= 0) return;
27459
- const { ctx, width, height, columns, theme, descriptors, hover } = params;
27930
+ const {
27931
+ ctx,
27932
+ width,
27933
+ height,
27934
+ columns,
27935
+ theme,
27936
+ descriptors,
27937
+ hover,
27938
+ getGroupingRemoveAnimationProgress
27939
+ } = params;
27460
27940
  ctx.save();
27461
27941
  ctx.fillStyle = theme.headerBackgroundColor;
27462
27942
  ctx.fillRect(0, 0, width, height);
@@ -27469,7 +27949,15 @@ function drawGroupingBar(params) {
27469
27949
  ctx.font = `${theme.headerFontWeight} ${theme.fontSize}px ${theme.fontFamily}`;
27470
27950
  ctx.textBaseline = "middle";
27471
27951
  ctx.fillText("\u5206\u7EC4\u680F", 12, height / 2);
27472
- drawGroupingPath({ ctx, height, columns, theme, descriptors, hover });
27952
+ drawGroupingPath({
27953
+ ctx,
27954
+ height,
27955
+ columns,
27956
+ theme,
27957
+ descriptors,
27958
+ hover,
27959
+ getGroupingRemoveAnimationProgress
27960
+ });
27473
27961
  descriptors.push({
27474
27962
  kind: "grouping-bar",
27475
27963
  rect: { x: 0, y: 0, width, height }
@@ -27477,7 +27965,15 @@ function drawGroupingBar(params) {
27477
27965
  ctx.restore();
27478
27966
  }
27479
27967
  function drawGroupingPath(params) {
27480
- const { ctx, height, columns, theme, descriptors, hover } = params;
27968
+ const {
27969
+ ctx,
27970
+ height,
27971
+ columns,
27972
+ theme,
27973
+ descriptors,
27974
+ hover,
27975
+ getGroupingRemoveAnimationProgress
27976
+ } = params;
27481
27977
  const itemHeight = Math.min(20, Math.max(height - 2, 0));
27482
27978
  const itemY = (height - itemHeight) / 2;
27483
27979
  const dividerX = 67.5;
@@ -27507,7 +28003,19 @@ function drawGroupingPath(params) {
27507
28003
  ctx.fillText(column.title, x + 4, height / 2);
27508
28004
  ctx.fillStyle = theme.mutedTextColor;
27509
28005
  ctx.font = `600 ${theme.fontSize + 2}px ${theme.fontFamily}`;
27510
- ctx.fillText("\xD7", x + itemWidth - 16, height / 2);
28006
+ const removeX = x + itemWidth - 16;
28007
+ const progress = getGroupingRemoveAnimationProgress?.(column.key) ?? 0;
28008
+ if (progress > 0) {
28009
+ const centerX = removeX + ctx.measureText("\xD7").width / 2;
28010
+ ctx.save();
28011
+ ctx.translate(centerX, height / 2);
28012
+ ctx.rotate(Math.PI / 2 * progress);
28013
+ ctx.textAlign = "center";
28014
+ ctx.fillText("\xD7", 0, 0);
28015
+ ctx.restore();
28016
+ } else {
28017
+ ctx.fillText("\xD7", removeX, height / 2);
28018
+ }
27511
28019
  descriptors.push({
27512
28020
  kind: "grouping-tag",
27513
28021
  rect: { x, y: itemY, width: itemWidth, height: itemHeight },
@@ -29146,14 +29654,26 @@ function showHeaderContextMenu(params) {
29146
29654
  }),
29147
29655
  onGetPrintData: resolveEnabledContextMenuFeatures(options.contextMenu).has(
29148
29656
  "print"
29149
- ) ? async () => {
29657
+ ) ? async (taskOptions) => {
29658
+ taskOptions?.signal?.throwIfAborted();
29150
29659
  const columns = getColumns().filter(
29151
29660
  (column) => column.hidden !== true && column.key !== ROW_SELECTION_COLUMN_KEY && column.key !== ROW_SELECTOR_COLUMN_KEY && column.key !== "__expanded_row__"
29152
29661
  );
29153
29662
  const rows = getRows();
29154
- const hasSummary = params.getExportSummaryEnabled?.() === true;
29663
+ const hasSummary = taskOptions?.includeSummary !== false && params.getExportSummaryEnabled?.() === true;
29155
29664
  const values = hasSummary ? await params.getPrintSummaryValues?.() : null;
29665
+ taskOptions?.signal?.throwIfAborted();
29156
29666
  const defaultKey = resolveDefaultSummaryTitleColumnKey(columns);
29667
+ const printRows = await mapInBatches(
29668
+ taskOptions?.rowLimit == null ? rows.length : Math.min(
29669
+ rows.length,
29670
+ Math.max(0, Math.floor(taskOptions.rowLimit))
29671
+ ),
29672
+ (rowIndex) => columns.map(
29673
+ (column) => getCellClipboardText(rows[rowIndex], rowIndex, column)
29674
+ ),
29675
+ taskOptions
29676
+ );
29157
29677
  return {
29158
29678
  columns: columns.map((column) => ({
29159
29679
  key: column.key,
@@ -29162,11 +29682,7 @@ function showHeaderContextMenu(params) {
29162
29682
  align: column.align ?? "left",
29163
29683
  overflow: column.ellipsis === true ? "ellipsis" : "wrap"
29164
29684
  })),
29165
- rows: rows.map(
29166
- (row, rowIndex) => columns.map(
29167
- (column) => getCellClipboardText(row, rowIndex, column)
29168
- )
29169
- ),
29685
+ rows: printRows,
29170
29686
  summaryRow: hasSummary ? columns.map(
29171
29687
  (column) => resolveSummaryCellDisplayValue(
29172
29688
  column,
@@ -29342,7 +29858,17 @@ function updateHeaderActionTooltip(params) {
29342
29858
  rect.x + rect.width / 2,
29343
29859
  rect.y + rect.height + 4
29344
29860
  );
29345
- tooltip.show(tooltipPoint.x, tooltipPoint.y, text);
29861
+ const topLeft = toViewportPoint(rect.x, rect.y);
29862
+ const bottomRight = toViewportPoint(
29863
+ rect.x + rect.width,
29864
+ rect.y + rect.height
29865
+ );
29866
+ tooltip.show(tooltipPoint.x, tooltipPoint.y, text, "default", {
29867
+ x: topLeft.x,
29868
+ y: topLeft.y,
29869
+ width: bottomRight.x - topLeft.x,
29870
+ height: bottomRight.y - topLeft.y
29871
+ });
29346
29872
  }
29347
29873
  function showDragTooltip(params) {
29348
29874
  const { tooltip, toViewportPoint, x, y, text, variant } = params;
@@ -30672,18 +31198,23 @@ var ListTableEventController = class {
30672
31198
  this.host.debugManager.getSnapshot()?.hitTest,
30673
31199
  result
30674
31200
  );
30675
- if (!hoverChanged && !hitChanged) {
31201
+ const editingSession = this.host.editingController.getSession();
31202
+ const updateBodyTooltip = () => {
31203
+ if (result.tooltipVariant === "error" && editingSession != null && editingSession.rowIndex === result.rowIndex && editingSession.columnKey === result.columnKey) {
31204
+ this.host.bodyTooltipController.clear();
31205
+ return;
31206
+ }
30676
31207
  this.host.bodyTooltipController.update(
30677
31208
  result,
30678
31209
  () => this.host.updateTooltip(result)
30679
31210
  );
31211
+ };
31212
+ if (!hoverChanged && !hitChanged) {
31213
+ updateBodyTooltip();
30680
31214
  return;
30681
31215
  }
30682
31216
  this.host.hover = nextHover;
30683
- this.host.bodyTooltipController.update(
30684
- result,
30685
- () => this.host.updateTooltip(result)
30686
- );
31217
+ updateBodyTooltip();
30687
31218
  this.host.scheduleRender(result);
30688
31219
  });
30689
31220
  __publicField(this, "handleMouseDown", (event) => {
@@ -31575,6 +32106,10 @@ var ListTableEventController = class {
31575
32106
  this.host.suppressNextClick = true;
31576
32107
  return;
31577
32108
  }
32109
+ if (result.area === "group-toggle" && result.contentKey) {
32110
+ this.host.toggleGroupRow?.(result.contentKey);
32111
+ return;
32112
+ }
31578
32113
  if (result.area !== "filter-trigger") {
31579
32114
  this.host.filterPanel.hide();
31580
32115
  }
@@ -34085,6 +34620,7 @@ function createListTableEventHost(core) {
34085
34620
  addGroupingColumns: (columnKeys) => core.addGroupingColumns(columnKeys),
34086
34621
  removeGroupingColumn: (columnKey) => core.removeGroupingColumn(columnKey),
34087
34622
  resetGrouping: () => core.resetGrouping(),
34623
+ toggleGroupRow: (rowKey) => core.toggleGroupRow?.(rowKey),
34088
34624
  isGroupingBarDropTarget: (clientX, clientY) => core.isGroupingBarDropTarget(clientX, clientY),
34089
34625
  setGroupingBarDropActive: (active) => core.setGroupingBarDropActive(active),
34090
34626
  toViewportPoint: (x, y) => core.domHost.toViewportPoint(x, y),
@@ -34606,8 +35142,14 @@ var ListTableOverlayController = class {
34606
35142
  this.runtime = options.runtime ?? createListTableOverlayRuntime();
34607
35143
  this.tooltipAdapter = {
34608
35144
  mount: () => void 0,
34609
- show: (x, y, content, variant) => {
34610
- this.showTooltip({ x, y, content, variant });
35145
+ show: (x, y, content, variant, anchorRect) => {
35146
+ this.showTooltip({
35147
+ x,
35148
+ y,
35149
+ content,
35150
+ variant,
35151
+ ...anchorRect ? { anchorRect } : {}
35152
+ });
34611
35153
  },
34612
35154
  hide: () => {
34613
35155
  this.hideTooltip();
@@ -34660,12 +35202,22 @@ var ListTableOverlayController = class {
34660
35202
  const options = this.getOptions();
34661
35203
  options.ui?.onTooltipRequest?.(nextRequest);
34662
35204
  if (!options.ui?.onTooltipRequest) {
34663
- this.componentPortal.tooltip.show(
34664
- nextRequest.x,
34665
- nextRequest.y,
34666
- nextRequest.content,
34667
- nextRequest.variant
34668
- );
35205
+ if (nextRequest.anchorRect) {
35206
+ this.componentPortal.tooltip.show(
35207
+ nextRequest.x,
35208
+ nextRequest.y,
35209
+ nextRequest.content,
35210
+ nextRequest.variant,
35211
+ nextRequest.anchorRect
35212
+ );
35213
+ } else {
35214
+ this.componentPortal.tooltip.show(
35215
+ nextRequest.x,
35216
+ nextRequest.y,
35217
+ nextRequest.content,
35218
+ nextRequest.variant
35219
+ );
35220
+ }
34669
35221
  }
34670
35222
  }
34671
35223
  hideTooltip() {
@@ -36008,6 +36560,8 @@ function publishListTableRender(params) {
36008
36560
  getControlAnimationProgress,
36009
36561
  getNestedTableHighlight,
36010
36562
  getExpandAnimationProgress,
36563
+ getGroupAnimationProgress,
36564
+ getGroupingRemoveAnimationProgress,
36011
36565
  getCollapseRowOffset,
36012
36566
  getCollapseCellHeight,
36013
36567
  getValidationMessage,
@@ -36047,6 +36601,8 @@ function publishListTableRender(params) {
36047
36601
  getControlAnimationProgress,
36048
36602
  getNestedTableHighlight,
36049
36603
  getExpandAnimationProgress,
36604
+ getGroupAnimationProgress,
36605
+ getGroupingRemoveAnimationProgress,
36050
36606
  getCollapseRowOffset,
36051
36607
  getCollapseCellHeight,
36052
36608
  getValidationMessage,
@@ -36373,6 +36929,8 @@ var ListTableRenderController = class {
36373
36929
  getControlAnimationProgress: publishAccessors.getControlAnimationProgress,
36374
36930
  getNestedTableHighlight: publishAccessors.getNestedTableHighlight,
36375
36931
  getExpandAnimationProgress: publishAccessors.getExpandAnimationProgress,
36932
+ getGroupAnimationProgress: publishAccessors.getGroupAnimationProgress,
36933
+ getGroupingRemoveAnimationProgress: publishAccessors.getGroupingRemoveAnimationProgress,
36376
36934
  getCollapseRowOffset: publishAccessors.getCollapseRowOffset,
36377
36935
  getCollapseCellHeight: publishAccessors.getCollapseCellHeight,
36378
36936
  getValidationMessage: publishAccessors.getValidationMessage,
@@ -36421,6 +36979,8 @@ var ListTableRenderController = class {
36421
36979
  selectedRowKeys: this.options.getSelectedRowKeys(),
36422
36980
  expandedRowKeys: this.options.getExpandedRowKeys(),
36423
36981
  collapsedRowKeys: this.options.getCollapsedRowKeys(),
36982
+ collapsedGroupKeys: this.options.getCollapsedGroupKeys?.() ?? [],
36983
+ groupHeightAnimation: this.options.getGroupHeightAnimation?.(),
36424
36984
  query: this.options.getQueryRuntimeState(),
36425
36985
  frozenRows: this.options.getFrozenRows(),
36426
36986
  draggingResize: this.options.isDraggingResize(),
@@ -37148,7 +37708,7 @@ var ListTableScrollToController = class {
37148
37708
  this.options.animationController.stopWheelScrollSmoothing();
37149
37709
  this.options.animationController.stopCarouselScrollAnimation();
37150
37710
  if (this.options.editingController.getSession()) {
37151
- this.options.editingController.close(false);
37711
+ this.options.editingController.commit();
37152
37712
  }
37153
37713
  if (request.behavior === "smooth") {
37154
37714
  this.options.animationController.startScrollToAnimation({
@@ -37910,6 +38470,10 @@ function assembleListTableCoreControllers(core, options) {
37910
38470
  const emitGroupingChange = () => {
37911
38471
  core.options.grouping?.onChange?.([...core.groupColumnKeys]);
37912
38472
  };
38473
+ const clearCollapsedGroups = () => {
38474
+ core.animationController?.stopGroupAnimations();
38475
+ core.collapsedGroupKeys = [];
38476
+ };
37913
38477
  const resetGroupingColumnHighlights = () => {
37914
38478
  core.selectionController.setSelectedHeaderState(
37915
38479
  core.selectionController.getSelectedHeaderKey(),
@@ -37954,6 +38518,7 @@ function assembleListTableCoreControllers(core, options) {
37954
38518
  (key, index) => key !== core.groupColumnKeys[index]
37955
38519
  )) {
37956
38520
  resetGroupingColumnHighlights();
38521
+ clearCollapsedGroups();
37957
38522
  }
37958
38523
  };
37959
38524
  core.setGroupingBarVisible = (visible) => {
@@ -37977,6 +38542,7 @@ function assembleListTableCoreControllers(core, options) {
37977
38542
  return;
37978
38543
  }
37979
38544
  core.groupColumnKeys = next;
38545
+ clearCollapsedGroups();
37980
38546
  resetGroupingColumnHighlights();
37981
38547
  core.storeFacade.scroll = { ...core.storeFacade.scroll, top: 0 };
37982
38548
  emitGroupingChange();
@@ -37988,6 +38554,7 @@ function assembleListTableCoreControllers(core, options) {
37988
38554
  return;
37989
38555
  }
37990
38556
  core.groupColumnKeys = next;
38557
+ clearCollapsedGroups();
37991
38558
  resetGroupingColumnHighlights();
37992
38559
  core.storeFacade.scroll = { ...core.storeFacade.scroll, top: 0 };
37993
38560
  emitGroupingChange();
@@ -37998,6 +38565,7 @@ function assembleListTableCoreControllers(core, options) {
37998
38565
  return;
37999
38566
  }
38000
38567
  core.groupColumnKeys = [];
38568
+ clearCollapsedGroups();
38001
38569
  resetGroupingColumnHighlights();
38002
38570
  core.storeFacade.scroll = { ...core.storeFacade.scroll, top: 0 };
38003
38571
  emitGroupingChange();
@@ -38052,6 +38620,7 @@ function assembleListTableCoreControllers(core, options) {
38052
38620
  getTableZoom: () => core.tableZoom,
38053
38621
  getLeafColumns: () => core.leafColumns,
38054
38622
  getDisplayData,
38623
+ getAllDisplayData: () => core.queryController.getDisplayData(),
38055
38624
  getDescriptors,
38056
38625
  getCurrentRenderSnapshot,
38057
38626
  getScroll: () => core.storeFacade.scroll,
@@ -38307,6 +38876,8 @@ function assembleListTableCoreControllers(core, options) {
38307
38876
  getSelectedRowKeys: () => core.storeFacade.selectedRowKeys,
38308
38877
  getExpandedRowKeys: () => core.storeFacade.expandedRowKeys,
38309
38878
  getCollapsedRowKeys: () => core.storeFacade.collapsedRowKeys,
38879
+ getCollapsedGroupKeys: () => core.collapsedGroupKeys,
38880
+ getGroupHeightAnimation: () => core.animationController.getGroupHeightAnimation(),
38310
38881
  getQueryRuntimeState,
38311
38882
  getFrozenRows: () => core.storeFacade.frozenRows,
38312
38883
  isDraggingResize: () => core.draggingResize != null,
@@ -38348,8 +38919,13 @@ function assembleListTableCoreControllers(core, options) {
38348
38919
  core.animationController.stopCarouselScroll();
38349
38920
  core.animationController.stopExpandAnimations();
38350
38921
  core.animationController.stopCollapseAnimations();
38922
+ core.animationController.stopGroupAnimations();
38923
+ core.animationController.stopGroupingRemoveAnimation();
38351
38924
  },
38352
38925
  beforePublish: (snapshot, resolveCellContents) => {
38926
+ core.animationController.reconcileGroupingRemoveHover(
38927
+ core.storeFacade.hover
38928
+ );
38353
38929
  if (core.animationController.shouldReconcileControlAnimations(snapshot)) {
38354
38930
  core.animationController.reconcileControlAnimations(
38355
38931
  snapshot,
@@ -38375,6 +38951,8 @@ function assembleListTableCoreControllers(core, options) {
38375
38951
  }),
38376
38952
  getNestedTableHighlight: (params) => core.animationController.getNestedTableHighlight(params),
38377
38953
  getExpandAnimationProgress: (rowKey) => core.animationController.getExpandAnimationProgress(rowKey),
38954
+ getGroupAnimationProgress: (rowKey) => core.animationController.getGroupAnimationProgress(rowKey),
38955
+ getGroupingRemoveAnimationProgress: (columnKey) => core.animationController.getGroupingRemoveAnimationProgress(columnKey),
38378
38956
  getCollapseRowOffset: (rowKey) => core.animationController.getCollapseRowOffset(rowKey),
38379
38957
  getCollapseCellHeight: (params) => core.animationController.getCollapseCellHeight(params),
38380
38958
  getValidationMessage: ({ record, rowIndex, columnKey }) => core.editingController.getValidationMessage(
@@ -38386,6 +38964,7 @@ function assembleListTableCoreControllers(core, options) {
38386
38964
  afterPublish: () => {
38387
38965
  core.animationController.ensureControlAnimationFrame();
38388
38966
  core.animationController.ensureExpandAnimationFrame();
38967
+ core.animationController.ensureGroupAnimationFrame();
38389
38968
  core.animationController.ensureCollapseAnimationFrame();
38390
38969
  core.carouselController.syncCarouselScroll();
38391
38970
  },
@@ -38482,6 +39061,45 @@ function assembleListTableCoreControllers(core, options) {
38482
39061
  addGroupingColumns: (columnKeys) => core.addGroupingColumns(columnKeys),
38483
39062
  removeGroupingColumn: (columnKey) => core.removeGroupingColumn(columnKey),
38484
39063
  resetGrouping: () => core.resetGrouping(),
39064
+ toggleGroupRow: (rowKey) => {
39065
+ const previous = core.animationController.getGroupHeightAnimation();
39066
+ if (previous && previous.rowKey !== rowKey) {
39067
+ core.animationController.finishGroupAnimations();
39068
+ render();
39069
+ }
39070
+ const collapsing = core.animationController.getGroupAnimationTarget(rowKey) === 0;
39071
+ const active = core.animationController.getGroupHeightAnimation();
39072
+ const geometry = active?.rowKey === rowKey ? {
39073
+ startOffset: active.startOffset,
39074
+ contentHeight: active.contentHeight,
39075
+ endRowIndex: active.endRowIndex
39076
+ } : resolveGroupHeightAnimationGeometry({
39077
+ snapshot: core.renderController.getCurrentRenderSnapshot(),
39078
+ options: core.options,
39079
+ rowKey,
39080
+ collapsedGroupKeys: core.collapsedGroupKeys.filter(
39081
+ (key) => key !== rowKey
39082
+ ),
39083
+ collapsedRowKeys: core.storeFacade.collapsedRowKeys,
39084
+ expandedRowKeys: core.storeFacade.expandedRowKeys
39085
+ });
39086
+ if (collapsing || core.collapsedGroupKeys.includes(rowKey)) {
39087
+ core.collapsedGroupKeys = core.collapsedGroupKeys.filter(
39088
+ (key) => key !== rowKey
39089
+ );
39090
+ core.animationController.startGroupAnimation(rowKey, true, geometry);
39091
+ } else {
39092
+ core.animationController.startGroupAnimation(
39093
+ rowKey,
39094
+ false,
39095
+ geometry,
39096
+ () => {
39097
+ core.collapsedGroupKeys = [...core.collapsedGroupKeys, rowKey];
39098
+ }
39099
+ );
39100
+ }
39101
+ render();
39102
+ },
38485
39103
  isGroupingBarDropTarget: (clientX, clientY) => {
38486
39104
  const point = core.canvasHost.getPointerPosition(clientX, clientY);
38487
39105
  return resolvePointerHit(point.x, point.y).area === "grouping-bar";
@@ -38539,8 +39157,85 @@ function assembleListTableCoreControllers(core, options) {
38539
39157
  core.groupColumnKeys = [
38540
39158
  ...options.grouping?.columnKeys ?? core.defaultGroupColumnKeys
38541
39159
  ];
39160
+ core.collapsedGroupKeys = [];
38542
39161
  core.tableZoom = 1;
38543
39162
  }
39163
+ function resolveGroupHeightAnimationGeometry(params) {
39164
+ const { snapshot } = params;
39165
+ const window2 = snapshot?.groupVisibleWindow;
39166
+ const index = snapshot?.groupIndex;
39167
+ const section = snapshot?.frozenRows.scroll;
39168
+ const rows = window2?.rows ?? section?.rows;
39169
+ const headerIndex = rows?.findIndex(
39170
+ (row) => row.kind === "group" && row.rowKey === params.rowKey
39171
+ ) ?? -1;
39172
+ if (!snapshot || !rows || !index || headerIndex < 0) {
39173
+ return { startOffset: 0, contentHeight: 0, endRowIndex: 0 };
39174
+ }
39175
+ const findNode = (nodes) => {
39176
+ for (const node2 of nodes) {
39177
+ if (node2.nodeKey === params.rowKey) return node2;
39178
+ const nested = findNode(node2.children ?? []);
39179
+ if (nested) return nested;
39180
+ }
39181
+ return void 0;
39182
+ };
39183
+ const node = findNode(index.root.children ?? []);
39184
+ if (!node) return { startOffset: 0, contentHeight: 0, endRowIndex: 0 };
39185
+ const visibilityPlan = buildListTableGroupVisibilityPlan({
39186
+ index,
39187
+ options: params.options,
39188
+ collapsedRowKeys: params.collapsedRowKeys,
39189
+ collapsedGroupKeys: params.collapsedGroupKeys,
39190
+ excludedRowKeys: [
39191
+ ...snapshot.frozenRows.top.rows.filter((row) => row.kind === "data").map((row) => row.rowKey),
39192
+ ...snapshot.frozenRows.bottom.rows.filter((row) => row.kind === "data").map((row) => row.rowKey)
39193
+ ]
39194
+ });
39195
+ const nodeRowCount = getGroupNodeVisibleRowCount(visibilityPlan, node);
39196
+ const detailPlan = buildListTableGroupExpandedRowPlan({
39197
+ index,
39198
+ options: params.options,
39199
+ expandedRowKeys: params.expandedRowKeys,
39200
+ rowHeight: snapshot.rowHeight,
39201
+ visibilityPlan
39202
+ });
39203
+ const details = detailPlan.supported ? detailPlan.plan.entries.filter(
39204
+ (entry) => entry.row.ownerDataRowIndex >= node.firstDataRowIndex && entry.row.ownerDataRowIndex < node.firstDataRowIndex + node.count
39205
+ ) : [];
39206
+ if (!window2) {
39207
+ const groupRow = rows[headerIndex];
39208
+ const nextPeerIndex = rows.findIndex(
39209
+ (row, rowIndex) => rowIndex > headerIndex && row.kind === "group" && row.depth <= (groupRow?.kind === "group" ? groupRow.depth : 0)
39210
+ );
39211
+ const endIndex = nextPeerIndex < 0 ? rows.length : nextPeerIndex;
39212
+ return {
39213
+ startOffset: sumVisibleRowHeights({
39214
+ rows,
39215
+ rowHeight: snapshot.rowHeight,
39216
+ end: headerIndex
39217
+ }),
39218
+ contentHeight: groupRow?.kind === "group" && groupRow.expanded ? sumVisibleRowHeights({
39219
+ rows,
39220
+ rowHeight: snapshot.rowHeight,
39221
+ start: headerIndex + 1,
39222
+ end: endIndex
39223
+ }) : (nodeRowCount - 1) * snapshot.rowHeight + details.reduce(
39224
+ (height, entry) => height + (entry.row.height ?? snapshot.rowHeight),
39225
+ 0
39226
+ ),
39227
+ endRowIndex: groupRow?.kind === "group" && groupRow.expanded ? section?.rowIndexMap?.[endIndex] ?? endIndex : (section?.rowIndexMap?.[headerIndex] ?? headerIndex) + nodeRowCount + details.length
39228
+ };
39229
+ }
39230
+ return {
39231
+ startOffset: window2.rowOffsetMap[headerIndex] ?? 0,
39232
+ contentHeight: (nodeRowCount - 1) * snapshot.rowHeight + details.reduce(
39233
+ (height, entry) => height + (entry.row.height ?? snapshot.rowHeight),
39234
+ 0
39235
+ ),
39236
+ endRowIndex: (window2.rowIndexMap[headerIndex] ?? 0) + nodeRowCount + details.length
39237
+ };
39238
+ }
38544
39239
  function collectGroupingColumnItems(columns) {
38545
39240
  return columns.flatMap((column) => {
38546
39241
  if (column.children?.length) {