@canvas-components/list-table 0.3.38 → 0.3.39

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