@canvas-components/list-table 0.2.7 → 0.3.1

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
@@ -980,6 +980,7 @@ function collectLeafColumns(columns) {
980
980
  // src/domain/constants.ts
981
981
  var DEFAULT_ROW_HEIGHT = 32;
982
982
  var DEFAULT_HEADER_ROW_HEIGHT = DEFAULT_ROW_HEIGHT;
983
+ var DEFAULT_SCROLLBAR_THICKNESS = 10;
983
984
  var HORIZONTAL_SCROLL_STEP = 120;
984
985
  var DEFAULT_SUMMARY_ROW_HEIGHT = DEFAULT_ROW_HEIGHT;
985
986
  var DEFAULT_EMPTY_BODY_HEIGHT = 96;
@@ -988,6 +989,7 @@ var FALLBACK_TABLE_WIDTH = 320;
988
989
  var FALLBACK_TABLE_HEIGHT = 240;
989
990
  var BODY_TOOLTIP_DELAY = 1e3;
990
991
  var TABLE_CONTENT_BORDER_SIZE = 2;
992
+ var TABLE_CONTENT_BORDER_RADIUS = 8;
991
993
  var SCROLL_OVERFLOW_EPSILON = 1;
992
994
  function resolveTableSize(value, fallback) {
993
995
  if (value == null) {
@@ -1048,6 +1050,7 @@ var ListTableDomHost = class {
1048
1050
  return this.nodes;
1049
1051
  }
1050
1052
  const wrapper = document.createElement("div");
1053
+ wrapper.className = "canvas-list-table-root";
1051
1054
  wrapper.style.position = "relative";
1052
1055
  wrapper.style.display = "flex";
1053
1056
  wrapper.style.flexDirection = "column";
@@ -1112,7 +1115,7 @@ var ListTableDomHost = class {
1112
1115
  );
1113
1116
  this.applyWrapperHeight();
1114
1117
  this.nodes.contentLayerElement.style.border = `1px solid ${theme.borderColor}`;
1115
- this.nodes.contentLayerElement.style.borderRadius = "0";
1118
+ this.nodes.contentLayerElement.style.borderRadius = `${TABLE_CONTENT_BORDER_RADIUS}px`;
1116
1119
  this.nodes.contentLayerElement.style.background = theme.backgroundColor;
1117
1120
  this.nodes.paginationElement.style.borderTop = `1px solid ${theme.borderColor}`;
1118
1121
  this.nodes.paginationElement.style.background = theme.backgroundColor;
@@ -1759,7 +1762,7 @@ var headerSelectionStateCache = /* @__PURE__ */ new WeakMap();
1759
1762
  var ROW_SELECTION_COLUMN_KEY = "__row_selection__";
1760
1763
  var ROW_SELECTOR_COLUMN_KEY = "__row_selector__";
1761
1764
  var EXPAND_COLUMN_KEY = "__row_expand__";
1762
- var DEFAULT_ROW_SELECTOR_WIDTH = 12;
1765
+ var DEFAULT_ROW_SELECTOR_WIDTH = DEFAULT_SCROLLBAR_THICKNESS;
1763
1766
  function getInitialSelectedRowKeys(options) {
1764
1767
  const rowSelection = options.rowSelection;
1765
1768
  if (!rowSelection) {
@@ -2548,8 +2551,14 @@ function getPriority(descriptor) {
2548
2551
  if (descriptor.kind === "body" && descriptor.fixed) {
2549
2552
  priority += 1;
2550
2553
  }
2554
+ if (isHeaderDescriptor(descriptor.kind) && descriptor.fixed) {
2555
+ priority += 3;
2556
+ }
2551
2557
  return priority;
2552
2558
  }
2559
+ function isHeaderDescriptor(kind) {
2560
+ return kind === "header" || kind === "header-selection" || kind === "header-action" || kind === "column-collapse-trigger" || kind === "resize-handle";
2561
+ }
2553
2562
  function getBasePriority(kind) {
2554
2563
  switch (kind) {
2555
2564
  case "grouping-remove":
@@ -6623,10 +6632,7 @@ function drawBodyCellContents(params) {
6623
6632
  return void 0;
6624
6633
  }
6625
6634
  const tooltipText = column.ellipsis === true && layout.truncated ? buildBodyContentsPlainText(contents) : void 0;
6626
- const blockHeight = Math.min(
6627
- layout.lines.length * lineHeight,
6628
- availableHeight
6629
- );
6635
+ const blockHeight = layout.lines.length * lineHeight;
6630
6636
  const contentTop = resolveContentTop(
6631
6637
  rect,
6632
6638
  blockHeight,
@@ -6635,9 +6641,9 @@ function drawBodyCellContents(params) {
6635
6641
  );
6636
6642
  const contentRect = {
6637
6643
  x: rect.x + paddingInline,
6638
- y: rect.y + paddingBlock,
6644
+ y: rect.y,
6639
6645
  width: availableWidth,
6640
- height: availableHeight
6646
+ height: rect.height
6641
6647
  };
6642
6648
  const contentVisibleRect = visibleRect ? intersectRects(contentRect, visibleRect) : contentRect;
6643
6649
  if (!contentVisibleRect) {
@@ -8040,23 +8046,24 @@ function resolveScrollbarRole(x, y, scrollbar) {
8040
8046
 
8041
8047
  // src/services/scrollbar-service.ts
8042
8048
  function resolvePointerHitWithScrollbars(result, x, y, scrollbarLayout) {
8043
- if (result.area !== "empty") {
8044
- return result;
8045
- }
8046
8049
  const horizontalScrollbar = scrollbarLayout.horizontal;
8047
8050
  if (horizontalScrollbar && isPointInScrollbar(x, y, horizontalScrollbar)) {
8051
+ const scrollbarRole = resolveScrollbarRole(x, y, horizontalScrollbar);
8048
8052
  return {
8049
8053
  area: "horizontal-scrollbar",
8050
8054
  columnKey: "__horizontal_scrollbar__",
8051
- scrollbarRole: resolveScrollbarRole(x, y, horizontalScrollbar)
8055
+ scrollbarRole,
8056
+ cursor: scrollbarRole === "thumb" ? "grab" : "pointer"
8052
8057
  };
8053
8058
  }
8054
8059
  const verticalScrollbar = scrollbarLayout.vertical;
8055
8060
  if (verticalScrollbar && isPointInScrollbar(x, y, verticalScrollbar)) {
8061
+ const scrollbarRole = resolveScrollbarRole(x, y, verticalScrollbar);
8056
8062
  return {
8057
8063
  area: "vertical-scrollbar",
8058
8064
  columnKey: "__vertical_scrollbar__",
8059
- scrollbarRole: resolveScrollbarRole(x, y, verticalScrollbar)
8065
+ scrollbarRole,
8066
+ cursor: scrollbarRole === "thumb" ? "grab" : "pointer"
8060
8067
  };
8061
8068
  }
8062
8069
  return result;
@@ -11575,6 +11582,9 @@ function resolveVisibleRowIndexForDataRow(params) {
11575
11582
  if (rowIndex >= params.rowCount) {
11576
11583
  return null;
11577
11584
  }
11585
+ if (params.frozenRows.scroll.dataRowIndexAligned) {
11586
+ return rowIndex;
11587
+ }
11578
11588
  for (const section of [
11579
11589
  params.frozenRows.top,
11580
11590
  params.frozenRows.scroll,
@@ -11598,7 +11608,7 @@ function resolveScrollTopForRowIndex(params) {
11598
11608
  if (frozenRows.top.rowIndexMap?.includes(rowIndex) || frozenRows.bottom.rowIndexMap?.includes(rowIndex)) {
11599
11609
  return null;
11600
11610
  }
11601
- const scrollSectionIndex = frozenRows.scroll.rowIndexMap ? frozenRows.scroll.rowIndexMap.indexOf(rowIndex) : rowIndex;
11611
+ const scrollSectionIndex = frozenRows.scroll.dataRowIndexAligned ? rowIndex : frozenRows.scroll.rowIndexMap ? frozenRows.scroll.rowIndexMap.indexOf(rowIndex) : rowIndex;
11602
11612
  if (scrollSectionIndex < 0) {
11603
11613
  return null;
11604
11614
  }
@@ -12947,69 +12957,55 @@ function matchFilterValue(rawValue, filterValue, optionValue = serializeFilterOp
12947
12957
  }
12948
12958
  function isMeaningfulFilterValue(value) {
12949
12959
  if ((value.filterType ?? "value") === "condition") {
12950
- return isSingleConditionActive(
12951
- value.conditionOperator ?? "none",
12952
- value.conditionValue?.trim() ?? "",
12953
- value.conditionSecondValue?.trim() ?? ""
12954
- ) || isSingleConditionActive(
12955
- value.secondConditionOperator ?? "none",
12956
- value.secondConditionValue?.trim() ?? "",
12957
- value.secondConditionSecondValue?.trim() ?? ""
12960
+ return resolveFilterConditions(value).some(
12961
+ (condition) => isSingleConditionActive(
12962
+ condition.operator,
12963
+ condition.value,
12964
+ condition.secondValue
12965
+ )
12958
12966
  );
12959
12967
  }
12960
12968
  return value.keyword.trim().length > 0 || (value.selectedKeys?.filter(Boolean).length ?? 0) > 0;
12961
12969
  }
12962
12970
  function matchConditionFilterValue(rawValue, filterValue) {
12963
12971
  const sourceText = stringifyFilterValue(rawValue).toLowerCase();
12964
- const firstOperator = filterValue.conditionOperator ?? "none";
12965
- const firstValue = filterValue.conditionValue?.trim().toLowerCase() ?? "";
12966
- const firstSecondValue = filterValue.conditionSecondValue?.trim().toLowerCase() ?? "";
12967
- const secondOperator = filterValue.secondConditionOperator ?? "none";
12968
- const secondValue = filterValue.secondConditionValue?.trim().toLowerCase() ?? "";
12969
- const secondSecondValue = filterValue.secondConditionSecondValue?.trim().toLowerCase() ?? "";
12970
- const relation = filterValue.conditionRelation ?? "and";
12971
- const hasFirst = isSingleConditionActive(
12972
- firstOperator,
12973
- firstValue,
12974
- firstSecondValue
12975
- );
12976
- const hasSecond = isSingleConditionActive(
12977
- secondOperator,
12978
- secondValue,
12979
- secondSecondValue
12972
+ const conditions = resolveFilterConditions(filterValue).filter(
12973
+ (condition) => isSingleConditionActive(
12974
+ condition.operator,
12975
+ condition.value,
12976
+ condition.secondValue
12977
+ )
12980
12978
  );
12981
- if (!hasFirst && !hasSecond) {
12979
+ const relation = filterValue.conditionRelation ?? "and";
12980
+ if (conditions.length === 0) {
12982
12981
  return true;
12983
12982
  }
12984
- if (!hasFirst) {
12985
- return evaluateCondition(
12986
- sourceText,
12987
- secondOperator,
12988
- secondValue,
12989
- secondSecondValue
12990
- );
12991
- }
12992
- if (!hasSecond) {
12993
- return evaluateCondition(
12994
- sourceText,
12995
- firstOperator,
12996
- firstValue,
12997
- firstSecondValue
12998
- );
12999
- }
13000
- const primaryResult = evaluateCondition(
13001
- sourceText,
13002
- firstOperator,
13003
- firstValue,
13004
- firstSecondValue
13005
- );
13006
- const secondaryResult = evaluateCondition(
12983
+ const matches = (condition) => evaluateCondition(
13007
12984
  sourceText,
13008
- secondOperator,
13009
- secondValue,
13010
- secondSecondValue
12985
+ condition.operator,
12986
+ condition.value,
12987
+ condition.secondValue
13011
12988
  );
13012
- return relation === "or" ? primaryResult || secondaryResult : primaryResult && secondaryResult;
12989
+ return relation === "or" ? conditions.some(matches) : conditions.every(matches);
12990
+ }
12991
+ function resolveFilterConditions(filterValue) {
12992
+ const source = filterValue.conditions?.length ? filterValue.conditions : [
12993
+ {
12994
+ operator: filterValue.conditionOperator ?? "none",
12995
+ value: filterValue.conditionValue,
12996
+ secondValue: filterValue.conditionSecondValue
12997
+ },
12998
+ {
12999
+ operator: filterValue.secondConditionOperator ?? "none",
13000
+ value: filterValue.secondConditionValue,
13001
+ secondValue: filterValue.secondConditionSecondValue
13002
+ }
13003
+ ];
13004
+ return source.map((condition) => ({
13005
+ operator: condition.operator,
13006
+ value: condition.value?.trim().toLowerCase() ?? "",
13007
+ secondValue: condition.secondValue?.trim().toLowerCase() ?? ""
13008
+ }));
13013
13009
  }
13014
13010
  function isSingleConditionActive(operator, conditionValue, conditionSecondValue) {
13015
13011
  if (!operator || operator === "none") {
@@ -13138,7 +13134,10 @@ var FILTER_PANEL_TEXTS = {
13138
13134
  relationAndLabel: "\u5E76\u4E14",
13139
13135
  relationOrLabel: "\u6216\u8005",
13140
13136
  resetAction: "\u91CD\u7F6E",
13141
- applyAction: "\u5E94\u7528"
13137
+ applyAction: "\u5E94\u7528",
13138
+ conditionLabel: "\u6761\u4EF6",
13139
+ addConditionAction: "\u65B0\u589E\u6761\u4EF6",
13140
+ deleteConditionAction: "\u5220\u9664\u6761\u4EF6"
13142
13141
  };
13143
13142
  var ASYNC_FILTER_OPTION_BATCH_SIZE = 2e4;
13144
13143
  function sortRows(rows, sortState, leafColumns) {
@@ -13236,7 +13235,8 @@ function buildFilterPanelValue(currentValue) {
13236
13235
  conditionRelation: currentValue.conditionRelation,
13237
13236
  secondConditionOperator: currentValue.secondConditionOperator,
13238
13237
  secondConditionValue: currentValue.secondConditionValue,
13239
- secondConditionSecondValue: currentValue.secondConditionSecondValue
13238
+ secondConditionSecondValue: currentValue.secondConditionSecondValue,
13239
+ conditions: currentValue.conditions
13240
13240
  };
13241
13241
  }
13242
13242
  function resolveFilterModes(column) {
@@ -13361,7 +13361,12 @@ function buildFilterStateValue(value) {
13361
13361
  conditionRelation: value.conditionRelation,
13362
13362
  secondConditionOperator: value.secondConditionOperator,
13363
13363
  secondConditionValue: value.secondConditionValue,
13364
- secondConditionSecondValue: value.secondConditionSecondValue
13364
+ secondConditionSecondValue: value.secondConditionSecondValue,
13365
+ conditions: value.conditions?.map((condition) => ({
13366
+ operator: condition.operator,
13367
+ value: condition.value,
13368
+ secondValue: condition.secondValue
13369
+ }))
13365
13370
  };
13366
13371
  }
13367
13372
  function toQueryFilters(filters) {
@@ -13682,6 +13687,9 @@ function showHeaderContextMenu(params) {
13682
13687
  return true;
13683
13688
  }
13684
13689
  function resolveContextMenuDensity(rowHeight) {
13690
+ if (rowHeight === "auto") {
13691
+ return "auto";
13692
+ }
13685
13693
  if (rowHeight === 56) {
13686
13694
  return "comfortable";
13687
13695
  }
@@ -15121,6 +15129,9 @@ var ListTableEventController = class {
15121
15129
  event.clientY
15122
15130
  );
15123
15131
  const result = this.host.resolvePointerHit(position.x, position.y);
15132
+ this.host.canvasHost.setCursor(
15133
+ result.area === "resize-handle" ? "col-resize" : result.cursor ?? ""
15134
+ );
15124
15135
  const nextHover = {
15125
15136
  rowIndex: result.rowIndex ?? null,
15126
15137
  columnKey: result.columnKey ?? null,
@@ -15143,9 +15154,6 @@ var ListTableEventController = class {
15143
15154
  result,
15144
15155
  () => this.host.updateTooltip(result)
15145
15156
  );
15146
- this.host.canvasHost.setCursor(
15147
- result.area === "resize-handle" ? "col-resize" : result.cursor ?? ""
15148
- );
15149
15157
  this.host.scheduleRender(result);
15150
15158
  });
15151
15159
  __publicField(this, "handleMouseDown", (event) => {
@@ -15316,6 +15324,9 @@ var ListTableEventController = class {
15316
15324
  if (!viewport) {
15317
15325
  return;
15318
15326
  }
15327
+ this.host.canvasHost.setCursor(
15328
+ result.scrollbarRole === "thumb" ? "grabbing" : "pointer"
15329
+ );
15319
15330
  if (result.scrollbarRole === "decrease-button") {
15320
15331
  this.stepScrollbar(result.area, -1, viewport);
15321
15332
  this.startContinuousScroll(result.area, -1, viewport);
@@ -15406,6 +15417,7 @@ var ListTableEventController = class {
15406
15417
  columnKey: null,
15407
15418
  area: "empty"
15408
15419
  };
15420
+ this.host.canvasHost.setCursor("");
15409
15421
  this.host.render();
15410
15422
  });
15411
15423
  __publicField(this, "handleContextMenu", (event) => {
@@ -16551,6 +16563,7 @@ var ListTableEventController = class {
16551
16563
  this.host.setGroupingBarDropActive?.(false);
16552
16564
  this.stopContinuousScroll();
16553
16565
  this.host.tooltip.hide();
16566
+ this.host.canvasHost.setCursor("");
16554
16567
  if (options?.unbindWindowEvents !== false) {
16555
16568
  this.host.canvasHost.unbindWindowDragEvents();
16556
16569
  }
@@ -17458,6 +17471,13 @@ function resolveToggleHeaderColumnVisibilityAction(params) {
17458
17471
 
17459
17472
  // src/shared/theme/density.ts
17460
17473
  function resolveDensitySizes(density) {
17474
+ if (density === "auto") {
17475
+ return {
17476
+ rowHeight: "auto",
17477
+ headerRowHeight: void 0,
17478
+ summaryRowHeight: void 0
17479
+ };
17480
+ }
17461
17481
  if (density === "comfortable") {
17462
17482
  return {
17463
17483
  rowHeight: 56,
@@ -18134,7 +18154,7 @@ function buildStoredColumnConfig(columns, sortState, filterState, zoom, summaryR
18134
18154
  filters: filterState,
18135
18155
  ...typeof zoom === "number" && Number.isFinite(zoom) && zoom > 0 ? { zoom } : null,
18136
18156
  ...typeof summaryRowHeight === "number" && Number.isFinite(summaryRowHeight) && summaryRowHeight >= 0 ? { summaryRowHeight } : null,
18137
- ...density === 32 || density === 48 || density === 56 ? { density } : null
18157
+ ...density === 32 || density === 48 || density === 56 || density === "auto" ? { density } : null
18138
18158
  };
18139
18159
  }
18140
18160
 
@@ -18184,7 +18204,7 @@ async function loadListTableStoredConfig(params) {
18184
18204
  filterState: stored.filters ? stored.filters : null,
18185
18205
  zoom: typeof stored.zoom === "number" && Number.isFinite(stored.zoom) && stored.zoom > 0 ? stored.zoom : null,
18186
18206
  summaryRowHeight: typeof stored.summaryRowHeight === "number" && Number.isFinite(stored.summaryRowHeight) && stored.summaryRowHeight >= 0 ? stored.summaryRowHeight : null,
18187
- density: stored.density === 32 || stored.density === 48 || stored.density === 56 ? stored.density : null
18207
+ density: stored.density === 32 || stored.density === 48 || stored.density === 56 || stored.density === "auto" ? stored.density : null
18188
18208
  };
18189
18209
  }
18190
18210
 
@@ -18217,11 +18237,12 @@ var ListTablePersistenceController = class {
18217
18237
  }
18218
18238
  let currentOptions = this.options.getOptions();
18219
18239
  if (stored.density != null) {
18240
+ const densitySizes = resolveDensitySizes(
18241
+ stored.density === "auto" ? "auto" : stored.density === 32 ? "compact" : stored.density === 56 ? "comfortable" : "middle"
18242
+ );
18220
18243
  currentOptions = {
18221
18244
  ...currentOptions,
18222
- rowHeight: stored.density,
18223
- headerRowHeight: stored.density,
18224
- summaryRowHeight: stored.density
18245
+ ...densitySizes
18225
18246
  };
18226
18247
  }
18227
18248
  if (stored.summaryRowHeight != null) {
@@ -18526,7 +18547,6 @@ function getMaxDepth(columns) {
18526
18547
  }
18527
18548
 
18528
18549
  // src/domain/layout/compute-scrollbar-layout.ts
18529
- var DEFAULT_SCROLLBAR_THICKNESS = 10;
18530
18550
  var DEFAULT_HORIZONTAL_LEFT = 0;
18531
18551
  var DEFAULT_HORIZONTAL_RIGHT = 0;
18532
18552
  var DEFAULT_HORIZONTAL_BOTTOM = 0;
@@ -20101,7 +20121,10 @@ function buildListTableRenderSnapshot(params) {
20101
20121
  baseRowsOverride,
20102
20122
  displayRowsOverride
20103
20123
  } = params;
20104
- const scrollbarThickness = options.scrollbar?.visible === false ? 0 : Math.max(options.scrollbar?.thickness ?? 10, 6);
20124
+ const scrollbarThickness = options.scrollbar?.visible === false ? 0 : Math.max(
20125
+ options.scrollbar?.thickness ?? DEFAULT_SCROLLBAR_THICKNESS,
20126
+ 6
20127
+ );
20105
20128
  let width = hostWidth;
20106
20129
  let height = hostHeight;
20107
20130
  const sourceNormalizedColumns = normalizeColumns(
@@ -20323,6 +20346,7 @@ function buildListTableRenderSnapshot(params) {
20323
20346
  let bodyState = resolveCurrentBodyState();
20324
20347
  if (plainRowWindow) {
20325
20348
  bodyState.frozenRows.scroll.windowed = true;
20349
+ bodyState.frozenRows.scroll.dataRowIndexAligned = true;
20326
20350
  bodyState.frozenRows.scroll.rowIndexMap = plainRowWindow.rowIndexMap;
20327
20351
  bodyState.frozenRows.scroll.rowOffsetMap = plainRowWindow.rowOffsetMap;
20328
20352
  bodyState.bodyLayout = resolveBodyLayout({
@@ -20346,6 +20370,7 @@ function buildListTableRenderSnapshot(params) {
20346
20370
  bodyState = resolveCurrentBodyState();
20347
20371
  if (plainRowWindow) {
20348
20372
  bodyState.frozenRows.scroll.windowed = true;
20373
+ bodyState.frozenRows.scroll.dataRowIndexAligned = true;
20349
20374
  bodyState.frozenRows.scroll.rowIndexMap = plainRowWindow.rowIndexMap;
20350
20375
  bodyState.frozenRows.scroll.rowOffsetMap = plainRowWindow.rowOffsetMap;
20351
20376
  bodyState.bodyLayout = resolveBodyLayout({
@@ -20392,6 +20417,7 @@ function buildListTableRenderSnapshot(params) {
20392
20417
  bodyState = resolveCurrentBodyState();
20393
20418
  if (plainRowWindow) {
20394
20419
  bodyState.frozenRows.scroll.windowed = true;
20420
+ bodyState.frozenRows.scroll.dataRowIndexAligned = true;
20395
20421
  bodyState.frozenRows.scroll.rowIndexMap = plainRowWindow.rowIndexMap;
20396
20422
  bodyState.frozenRows.scroll.rowOffsetMap = plainRowWindow.rowOffsetMap;
20397
20423
  bodyState.bodyLayout = resolveBodyLayout({
@@ -20912,7 +20938,7 @@ function resolveAutoRowHeightMeasureRows(rows, sampleCount = AUTO_ROW_HEIGHT_SAM
20912
20938
  return rows.slice(0, sampleCount);
20913
20939
  }
20914
20940
  function resolveListTableHeaderRowHeight(params) {
20915
- return params.headerRowHeight ?? (params.rowHeight === "auto" ? DEFAULT_ROW_HEIGHT : params.resolvedRowHeight);
20941
+ return params.headerRowHeight ?? params.resolvedRowHeight;
20916
20942
  }
20917
20943
  function buildListTableDebugSnapshot(params) {
20918
20944
  const {
@@ -21074,13 +21100,28 @@ function resolveListTableRenderHostSize(params) {
21074
21100
  }
21075
21101
 
21076
21102
  // src/rendering/primitives/draw-scrollbars.ts
21077
- function drawScrollbars(ctx, layout, descriptors, borderColor, opacity = 1, interactive = true) {
21103
+ function drawScrollbars(ctx, layout, descriptors, borderColor, opacity = 1, interactive = true, verticalFrame) {
21078
21104
  const alpha = Number.isFinite(opacity) ? Math.min(Math.max(opacity, 0), 1) : 1;
21079
21105
  if (alpha <= 1e-3) {
21080
21106
  return;
21081
21107
  }
21082
21108
  ctx.save();
21083
21109
  ctx.globalAlpha = alpha;
21110
+ if (layout.horizontal && verticalFrame) {
21111
+ drawHorizontalScrollbarMask(
21112
+ ctx,
21113
+ layout.horizontal,
21114
+ verticalFrame.bodyBackgroundColor
21115
+ );
21116
+ }
21117
+ if (layout.vertical && verticalFrame) {
21118
+ drawVerticalScrollbarFrame(
21119
+ ctx,
21120
+ layout.vertical,
21121
+ verticalFrame,
21122
+ borderColor
21123
+ );
21124
+ }
21084
21125
  if (layout.horizontal) {
21085
21126
  drawAxisScrollbar(
21086
21127
  ctx,
@@ -21101,6 +21142,45 @@ function drawScrollbars(ctx, layout, descriptors, borderColor, opacity = 1, inte
21101
21142
  interactive
21102
21143
  );
21103
21144
  }
21145
+ if (layout.horizontal) {
21146
+ drawHorizontalScrollbarTopBorder(
21147
+ ctx,
21148
+ layout.horizontal,
21149
+ layout.vertical,
21150
+ borderColor
21151
+ );
21152
+ }
21153
+ ctx.restore();
21154
+ }
21155
+ function drawHorizontalScrollbarMask(ctx, layout, backgroundColor) {
21156
+ const left = layout.decreaseButton.x;
21157
+ const right = layout.increaseButton.x + layout.increaseButton.width;
21158
+ const top = layout.decreaseButton.y;
21159
+ const height = layout.decreaseButton.height;
21160
+ if (right <= left || height <= 0) {
21161
+ return;
21162
+ }
21163
+ ctx.save();
21164
+ ctx.fillStyle = backgroundColor;
21165
+ ctx.fillRect(left, top, right - left, height);
21166
+ ctx.restore();
21167
+ }
21168
+ function drawHorizontalScrollbarTopBorder(ctx, horizontal, vertical, borderColor) {
21169
+ const left = Math.round(horizontal.decreaseButton.x) + 0.5;
21170
+ const horizontalRight = horizontal.increaseButton.x + horizontal.increaseButton.width;
21171
+ const verticalRight = vertical ? vertical.decreaseButton.x + vertical.decreaseButton.width : horizontalRight;
21172
+ const right = Math.round(Math.max(horizontalRight, verticalRight)) - 0.5;
21173
+ const top = Math.round(horizontal.decreaseButton.y) + 0.5;
21174
+ if (right <= left) {
21175
+ return;
21176
+ }
21177
+ ctx.save();
21178
+ ctx.strokeStyle = borderColor;
21179
+ ctx.lineWidth = 1;
21180
+ ctx.beginPath();
21181
+ ctx.moveTo(left, top);
21182
+ ctx.lineTo(right, top);
21183
+ ctx.stroke();
21104
21184
  ctx.restore();
21105
21185
  }
21106
21186
  function drawAxisScrollbar(ctx, layout, axis, descriptors, borderColor, interactive) {
@@ -21131,19 +21211,69 @@ function drawAxisScrollbar(ctx, layout, axis, descriptors, borderColor, interact
21131
21211
  scrollbarRole: "increase-button"
21132
21212
  });
21133
21213
  }
21134
- drawTrack(ctx, layout.track, borderColor);
21135
21214
  drawButton(ctx, layout.decreaseButton, axis, "decrease");
21136
21215
  drawButton(ctx, layout.increaseButton, axis, "increase");
21137
21216
  drawThumb(ctx, layout.thumb);
21217
+ drawTrackBorder(ctx, layout.track, axis, borderColor);
21218
+ }
21219
+ function drawTrackBorder(ctx, rect, axis, borderColor) {
21220
+ const left = Math.round(rect.x) + 0.5;
21221
+ const right = Math.round(rect.x + rect.width) - 0.5;
21222
+ const top = Math.round(rect.y) + 0.5;
21223
+ const bottom = Math.round(rect.y + rect.height) - 0.5;
21224
+ if (right <= left || bottom <= top) {
21225
+ return;
21226
+ }
21227
+ ctx.save();
21228
+ ctx.strokeStyle = borderColor;
21229
+ ctx.lineWidth = 1;
21230
+ ctx.beginPath();
21231
+ if (axis === "horizontal") {
21232
+ ctx.moveTo(left, top);
21233
+ ctx.lineTo(right, top);
21234
+ } else {
21235
+ ctx.moveTo(left, top);
21236
+ ctx.lineTo(left, bottom);
21237
+ }
21238
+ ctx.stroke();
21239
+ ctx.restore();
21138
21240
  }
21139
- function drawTrack(ctx, rect, borderColor) {
21241
+ function drawVerticalScrollbarFrame(ctx, layout, frame, borderColor) {
21242
+ const left = Math.round(layout.decreaseButton.x) + 0.5;
21243
+ const right = Math.round(layout.decreaseButton.x + layout.decreaseButton.width) - 0.5;
21244
+ const top = Math.round(frame.top) + 0.5;
21245
+ const bottom = Math.round(frame.top + frame.height) - 0.5;
21246
+ const headerBottom = Math.round(frame.headerBottom) + 0.5;
21247
+ if (right <= left || bottom <= top) {
21248
+ return;
21249
+ }
21140
21250
  ctx.save();
21141
- ctx.fillStyle = "rgba(148, 163, 184, 0.16)";
21251
+ ctx.fillStyle = frame.headerBackgroundColor;
21252
+ ctx.fillRect(
21253
+ layout.decreaseButton.x,
21254
+ frame.top,
21255
+ layout.decreaseButton.width,
21256
+ Math.max(frame.headerBottom - frame.top, 0)
21257
+ );
21258
+ ctx.fillStyle = frame.bodyBackgroundColor;
21259
+ ctx.fillRect(
21260
+ layout.decreaseButton.x,
21261
+ frame.headerBottom,
21262
+ layout.decreaseButton.width,
21263
+ Math.max(frame.top + frame.height - frame.headerBottom, 0)
21264
+ );
21142
21265
  ctx.strokeStyle = borderColor;
21143
21266
  ctx.lineWidth = 1;
21144
- roundRect(ctx, rect.x, rect.y, rect.width, rect.height, rect.height / 2);
21145
- ctx.fill();
21267
+ ctx.beginPath();
21268
+ ctx.moveTo(left, top);
21269
+ ctx.lineTo(left, bottom);
21146
21270
  ctx.stroke();
21271
+ if (headerBottom > top && headerBottom < bottom) {
21272
+ ctx.beginPath();
21273
+ ctx.moveTo(left, headerBottom);
21274
+ ctx.lineTo(right, headerBottom);
21275
+ ctx.stroke();
21276
+ }
21147
21277
  ctx.restore();
21148
21278
  }
21149
21279
  function drawThumb(ctx, rect) {
@@ -21155,34 +21285,25 @@ function drawThumb(ctx, rect) {
21155
21285
  }
21156
21286
  function drawButton(ctx, rect, axis, direction) {
21157
21287
  ctx.save();
21158
- ctx.fillStyle = "rgba(226, 232, 240, 0.92)";
21159
- ctx.strokeStyle = "rgba(148, 163, 184, 0.65)";
21160
- ctx.lineWidth = 1;
21161
- roundRect(ctx, rect.x, rect.y, rect.width, rect.height, rect.height / 2);
21162
- ctx.fill();
21163
- ctx.stroke();
21164
21288
  ctx.fillStyle = "rgba(71, 85, 105, 0.88)";
21165
21289
  ctx.beginPath();
21290
+ const centerX = rect.x + rect.width / 2;
21291
+ const centerY = rect.y + rect.height / 2;
21292
+ const iconSize = Math.min(rect.width, rect.height) * 0.64;
21293
+ const directionOffset = iconSize * 0.4;
21294
+ const crossAxisOffset = iconSize / 2;
21166
21295
  if (axis === "horizontal") {
21167
- const centerY = rect.y + rect.height / 2;
21168
- const iconWidth = rect.width * 0.28;
21169
- const iconHeight = rect.height * 0.22;
21170
- const centerX = rect.x + rect.width / 2;
21171
- const tipX = direction === "decrease" ? centerX - iconWidth / 2 : centerX + iconWidth / 2;
21172
- const tailX = direction === "decrease" ? centerX + iconWidth / 2 : centerX - iconWidth / 2;
21296
+ const tipX = centerX + (direction === "decrease" ? -1 : 1) * directionOffset;
21297
+ const tailX = centerX + (direction === "decrease" ? 1 : -1) * directionOffset;
21173
21298
  ctx.moveTo(tipX, centerY);
21174
- ctx.lineTo(tailX, centerY - iconHeight);
21175
- ctx.lineTo(tailX, centerY + iconHeight);
21299
+ ctx.lineTo(tailX, centerY - crossAxisOffset);
21300
+ ctx.lineTo(tailX, centerY + crossAxisOffset);
21176
21301
  } else {
21177
- const centerX = rect.x + rect.width / 2;
21178
- const iconWidth = rect.width * 0.22;
21179
- const iconHeight = rect.height * 0.28;
21180
- const centerY = rect.y + rect.height / 2;
21181
- const tipY = direction === "decrease" ? centerY - iconHeight / 2 : centerY + iconHeight / 2;
21182
- const tailY = direction === "decrease" ? centerY + iconHeight / 2 : centerY - iconHeight / 2;
21302
+ const tipY = centerY + (direction === "decrease" ? -1 : 1) * directionOffset;
21303
+ const tailY = centerY + (direction === "decrease" ? 1 : -1) * directionOffset;
21183
21304
  ctx.moveTo(centerX, tipY);
21184
- ctx.lineTo(centerX - iconWidth, tailY);
21185
- ctx.lineTo(centerX + iconWidth, tailY);
21305
+ ctx.lineTo(centerX - crossAxisOffset, tailY);
21306
+ ctx.lineTo(centerX + crossAxisOffset, tailY);
21186
21307
  }
21187
21308
  ctx.closePath();
21188
21309
  ctx.fill();
@@ -23110,7 +23231,8 @@ function drawHeaderCell(params, cell, clipRect) {
23110
23231
  descriptors.push({
23111
23232
  kind: "header",
23112
23233
  rect,
23113
- columnKey: cell.node.key
23234
+ columnKey: cell.node.key,
23235
+ fixed: cell.node.fixed
23114
23236
  });
23115
23237
  if (params.rowSelection.type === "checkbox") {
23116
23238
  drawHeaderSelectionControl(params, rect);
@@ -23118,7 +23240,8 @@ function drawHeaderCell(params, cell, clipRect) {
23118
23240
  kind: "header-selection",
23119
23241
  rect: getHeaderSelectionRect(rect),
23120
23242
  columnKey: cell.node.key,
23121
- controlType: params.rowSelection.type
23243
+ controlType: params.rowSelection.type,
23244
+ fixed: cell.node.fixed
23122
23245
  });
23123
23246
  }
23124
23247
  ctx.restore();
@@ -23128,7 +23251,8 @@ function drawHeaderCell(params, cell, clipRect) {
23128
23251
  descriptors.push({
23129
23252
  kind: "header",
23130
23253
  rect,
23131
- columnKey: cell.node.key
23254
+ columnKey: cell.node.key,
23255
+ fixed: cell.node.fixed
23132
23256
  });
23133
23257
  ctx.restore();
23134
23258
  return;
@@ -23177,12 +23301,25 @@ function drawHeaderCell(params, cell, clipRect) {
23177
23301
  textLayout,
23178
23302
  titleContent,
23179
23303
  ctx
23180
- )
23304
+ ),
23305
+ fixed: cell.node.fixed
23181
23306
  });
23182
23307
  if (cell.node.children.length === 0) {
23183
- drawCollapsedColumnMarkers(params, rect, cell.node.key, collapseMarkerSet);
23184
- drawHeaderActions(params, rect, cell.node.key, visibleState);
23185
- drawResizeHandles(params, rect, cell.node.key);
23308
+ drawCollapsedColumnMarkers(
23309
+ params,
23310
+ rect,
23311
+ cell.node.key,
23312
+ collapseMarkerSet,
23313
+ cell.node.fixed
23314
+ );
23315
+ drawHeaderActions(
23316
+ params,
23317
+ rect,
23318
+ cell.node.key,
23319
+ visibleState,
23320
+ cell.node.fixed
23321
+ );
23322
+ drawResizeHandles(params, rect, cell.node.key, cell.node.fixed);
23186
23323
  }
23187
23324
  ctx.restore();
23188
23325
  }
@@ -23220,7 +23357,7 @@ function measureHeaderContentWidth(ctx, contents) {
23220
23357
  0
23221
23358
  ) + Math.max(contents.length - 1, 0) * gap;
23222
23359
  }
23223
- function drawHeaderActions(params, rect, columnKey, visibilityState) {
23360
+ function drawHeaderActions(params, rect, columnKey, visibilityState, fixed) {
23224
23361
  if (!visibilityState.visible) {
23225
23362
  return;
23226
23363
  }
@@ -23273,7 +23410,8 @@ function drawHeaderActions(params, rect, columnKey, visibilityState) {
23273
23410
  rect: actionRect,
23274
23411
  columnKey,
23275
23412
  actionType,
23276
- visibilityState
23413
+ visibilityState,
23414
+ fixed
23277
23415
  });
23278
23416
  });
23279
23417
  }
@@ -23295,15 +23433,15 @@ function resolveCollapsedColumnMarkerSet(markers, columnKey) {
23295
23433
  hasRightMarker: !!right
23296
23434
  };
23297
23435
  }
23298
- function drawCollapsedColumnMarkers(params, rect, columnKey, markerSet) {
23436
+ function drawCollapsedColumnMarkers(params, rect, columnKey, markerSet, fixed) {
23299
23437
  if (markerSet.left) {
23300
- drawCollapsedColumnMarker(params, rect, columnKey, markerSet.left);
23438
+ drawCollapsedColumnMarker(params, rect, columnKey, markerSet.left, fixed);
23301
23439
  }
23302
23440
  if (markerSet.right) {
23303
- drawCollapsedColumnMarker(params, rect, columnKey, markerSet.right);
23441
+ drawCollapsedColumnMarker(params, rect, columnKey, markerSet.right, fixed);
23304
23442
  }
23305
23443
  }
23306
- function drawCollapsedColumnMarker(params, rect, columnKey, marker) {
23444
+ function drawCollapsedColumnMarker(params, rect, columnKey, marker, fixed) {
23307
23445
  const triggerRect = {
23308
23446
  x: marker.align === "left" ? rect.x + GRID_LINE_OFFSET2 - COLLAPSE_TRIGGER_WIDTH / 2 : rect.x + rect.width + GRID_LINE_OFFSET2 - COLLAPSE_TRIGGER_WIDTH / 2,
23309
23447
  y: rect.y + (rect.height - COLLAPSE_TRIGGER_HEIGHT) / 2,
@@ -23317,7 +23455,8 @@ function drawCollapsedColumnMarker(params, rect, columnKey, marker) {
23317
23455
  rect: triggerRect,
23318
23456
  columnKey,
23319
23457
  cursor: "pointer",
23320
- contentKey: `${marker.rangeStart}:${marker.rangeEnd}`
23458
+ contentKey: `${marker.rangeStart}:${marker.rangeEnd}`,
23459
+ fixed
23321
23460
  });
23322
23461
  }
23323
23462
  function isHeaderCellSelected(params, columnKey, rect) {
@@ -23339,13 +23478,14 @@ function isHeaderCellInRange(rangeHighlight, cell) {
23339
23478
  function isSameRect(left, right) {
23340
23479
  return Math.abs(left.x - right.x) <= 1 && Math.abs(left.y - right.y) <= 1 && Math.abs(left.width - right.width) <= 1 && Math.abs(left.height - right.height) <= 1;
23341
23480
  }
23342
- function drawResizeHandles(params, rect, columnKey) {
23481
+ function drawResizeHandles(params, rect, columnKey, fixed) {
23343
23482
  if (params.isResizable(columnKey)) {
23344
23483
  params.descriptors.push({
23345
23484
  kind: "resize-handle",
23346
23485
  rect: getResizeHandleRect(params, rect, "right"),
23347
23486
  columnKey,
23348
- resizeEdge: "right"
23487
+ resizeEdge: "right",
23488
+ fixed
23349
23489
  });
23350
23490
  }
23351
23491
  const leafIndex = params.leafColumnKeys?.indexOf(columnKey) ?? -1;
@@ -23355,7 +23495,8 @@ function drawResizeHandles(params, rect, columnKey) {
23355
23495
  kind: "resize-handle",
23356
23496
  rect: getResizeHandleRect(params, rect, "left"),
23357
23497
  columnKey: previousColumnKey,
23358
- resizeEdge: "left"
23498
+ resizeEdge: "left",
23499
+ fixed
23359
23500
  });
23360
23501
  }
23361
23502
  }
@@ -23749,15 +23890,18 @@ function resolveActiveCellOverlayLayout(params) {
23749
23890
  const descriptor = selection.rowIndex != null && selection.columnKey != null ? params.descriptors.find(
23750
23891
  (item) => item.kind === "body" && item.rowIndex === selection.rowIndex && item.columnKey === selection.columnKey
23751
23892
  ) : void 0;
23752
- const rangeRects = resolveRangeHighlightLayouts({
23893
+ const rangeLayout = resolveRangeHighlightLayouts({
23753
23894
  descriptors: params.descriptors,
23754
23895
  rangeHighlight: params.rangeHighlight,
23755
23896
  highlightMode: params.highlightMode,
23756
23897
  columnKeys: params.columnKeys ?? [],
23757
23898
  allowColumnRange: selection.rowIndex == null,
23758
23899
  allowRowRange: selection.columnKey === ROW_SELECTOR_COLUMN_KEY,
23759
- resolveClipRect: (item) => resolveActiveCellSectionClipRect(item, params)
23900
+ resolveClipRect: (item) => resolveActiveCellSectionClipRect(item, params),
23901
+ width: params.width,
23902
+ height: params.height
23760
23903
  });
23904
+ const rangeRects = rangeLayout.rects;
23761
23905
  if (!descriptor && rangeRects.length === 0) {
23762
23906
  return null;
23763
23907
  }
@@ -23768,6 +23912,7 @@ function resolveActiveCellOverlayLayout(params) {
23768
23912
  return {
23769
23913
  rect: descriptor?.rect ?? { x: 0, y: 0, width: 0, height: 0 },
23770
23914
  clipRect,
23915
+ rangeSegments: rangeLayout.segments,
23771
23916
  rangeRects
23772
23917
  };
23773
23918
  }
@@ -23776,14 +23921,44 @@ function drawActiveCellOverlay(params) {
23776
23921
  return;
23777
23922
  }
23778
23923
  const { ctx, layout } = params;
23779
- layout.rangeRects.forEach(({ rect, clipRect, omitLeft, omitRight }) => {
23780
- ctx.save();
23781
- ctx.beginPath();
23782
- ctx.rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
23783
- ctx.clip();
23784
- drawRangeHighlightBorder(ctx, rect, { omitLeft, omitRight });
23785
- ctx.restore();
23786
- });
23924
+ if (layout.rangeSegments?.length) {
23925
+ layout.rangeSegments.forEach((segment) => {
23926
+ ctx.save();
23927
+ ctx.beginPath();
23928
+ ctx.rect(
23929
+ segment.clipRect.x,
23930
+ segment.clipRect.y,
23931
+ segment.clipRect.width,
23932
+ segment.clipRect.height
23933
+ );
23934
+ ctx.clip();
23935
+ ctx.strokeStyle = "#1677ff";
23936
+ ctx.lineWidth = 1;
23937
+ ctx.beginPath();
23938
+ ctx.moveTo(segment.startX, segment.startY);
23939
+ if (segment.controlX != null && segment.controlY != null) {
23940
+ ctx.quadraticCurveTo(
23941
+ segment.controlX,
23942
+ segment.controlY,
23943
+ segment.endX,
23944
+ segment.endY
23945
+ );
23946
+ } else {
23947
+ ctx.lineTo(segment.endX, segment.endY);
23948
+ }
23949
+ ctx.stroke();
23950
+ ctx.restore();
23951
+ });
23952
+ } else {
23953
+ layout.rangeRects.forEach(({ rect, clipRect, omitLeft, omitRight }) => {
23954
+ ctx.save();
23955
+ ctx.beginPath();
23956
+ ctx.rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
23957
+ ctx.clip();
23958
+ drawRangeHighlightBorder(ctx, rect, { omitLeft, omitRight });
23959
+ ctx.restore();
23960
+ });
23961
+ }
23787
23962
  if (layout.rangeRects.length === 0 && layout.rect.width > 0 && layout.rect.height > 0) {
23788
23963
  ctx.save();
23789
23964
  ctx.beginPath();
@@ -23804,17 +23979,19 @@ function resolveRangeHighlightLayouts(params) {
23804
23979
  const cellRange = params.rangeHighlight?.selectedCellRange;
23805
23980
  const rowSelectorRange = rowRange && params.allowRowRange;
23806
23981
  if (!cellRange && !rowSelectorRange && (!columnRange || !params.allowColumnRange)) {
23807
- return [];
23982
+ return { rects: [], segments: [] };
23808
23983
  }
23809
23984
  const bodyDescriptors = params.descriptors.filter(
23810
23985
  (item) => item.kind === "body" && item.columnKey != null && item.rowIndex != null
23811
23986
  );
23812
23987
  const selected = bodyDescriptors.filter((item) => {
23813
- const rowSelected = rowRange != null && item.rowIndex >= rowRange.start && item.rowIndex <= rowRange.end;
23988
+ const itemRowStart = item.rowIndex;
23989
+ const itemRowEnd = itemRowStart + Math.max(item.rowSpan ?? 1, 1) - 1;
23990
+ const rowSelected = rowRange != null && itemRowEnd >= rowRange.start && itemRowStart <= rowRange.end;
23814
23991
  const columnIndex = params.columnKeys.indexOf(item.columnKey);
23815
23992
  const columnSelected = columnRange != null && columnIndex >= columnRange.start && columnIndex <= columnRange.end;
23816
23993
  if (cellRange) {
23817
- return item.rowIndex >= cellRange.startRowIndex && item.rowIndex <= cellRange.endRowIndex && columnIndex >= cellRange.startColumnIndex && columnIndex <= cellRange.endColumnIndex;
23994
+ return itemRowEnd >= cellRange.startRowIndex && itemRowStart <= cellRange.endRowIndex && columnIndex >= cellRange.startColumnIndex && columnIndex <= cellRange.endColumnIndex;
23818
23995
  }
23819
23996
  if (rowSelectorRange) {
23820
23997
  return rowSelected;
@@ -23850,7 +24027,7 @@ function resolveRangeHighlightLayouts(params) {
23850
24027
  layer.push(range);
23851
24028
  groupedByLayer.set(key, layer);
23852
24029
  });
23853
- return ranges.map((range) => {
24030
+ const rects = ranges.map((range) => {
23854
24031
  const layer = groupedByLayer.get(`${range.rect.y}:${range.rect.height}`) ?? [];
23855
24032
  const minX = Math.min(...layer.map((item) => item.rect.x));
23856
24033
  const maxX = Math.max(
@@ -23862,6 +24039,172 @@ function resolveRangeHighlightLayouts(params) {
23862
24039
  omitRight: range.rect.x + range.rect.width < maxX
23863
24040
  };
23864
24041
  });
24042
+ return {
24043
+ rects,
24044
+ segments: roundRangeBorderAtTableBottom(
24045
+ resolveRangeBorderSegments(selected, params.resolveClipRect),
24046
+ params.width,
24047
+ params.height
24048
+ )
24049
+ };
24050
+ }
24051
+ function roundRangeBorderAtTableBottom(segments, width, height) {
24052
+ const inset = 0.5;
24053
+ const left = inset;
24054
+ const right = width - inset;
24055
+ const bottom = height - inset;
24056
+ const radius = Math.max(
24057
+ TABLE_CONTENT_BORDER_RADIUS - TABLE_CONTENT_BORDER_SIZE / 2,
24058
+ 0
24059
+ );
24060
+ if (radius <= 0) return segments;
24061
+ const rounded = segments.map((segment) => ({ ...segment }));
24062
+ const curves = [];
24063
+ const bottomSegments = rounded.filter(
24064
+ (segment) => nearlyEqual(segment.startY, bottom) && nearlyEqual(segment.endY, bottom)
24065
+ );
24066
+ const leftBottom = bottomSegments.find(
24067
+ (segment) => nearlyEqual(segment.startX, left)
24068
+ );
24069
+ const leftSide = rounded.find(
24070
+ (segment) => nearlyEqual(segment.startX, left) && nearlyEqual(segment.endX, left) && nearlyEqual(segment.endY, bottom)
24071
+ );
24072
+ if (leftBottom && leftSide) {
24073
+ leftBottom.startX = Math.min(left + radius, leftBottom.endX);
24074
+ leftSide.endY = Math.max(bottom - radius, leftSide.startY);
24075
+ curves.push({
24076
+ startX: leftSide.endX,
24077
+ startY: leftSide.endY,
24078
+ controlX: left,
24079
+ controlY: bottom,
24080
+ endX: leftBottom.startX,
24081
+ endY: leftBottom.startY,
24082
+ clipRect: leftSide.clipRect
24083
+ });
24084
+ }
24085
+ const rightBottom = bottomSegments.find(
24086
+ (segment) => nearlyEqual(segment.endX, right)
24087
+ );
24088
+ const rightSide = rounded.find(
24089
+ (segment) => nearlyEqual(segment.startX, right) && nearlyEqual(segment.endX, right) && nearlyEqual(segment.endY, bottom)
24090
+ );
24091
+ if (rightBottom && rightSide) {
24092
+ rightBottom.endX = Math.max(right - radius, rightBottom.startX);
24093
+ rightSide.endY = Math.max(bottom - radius, rightSide.startY);
24094
+ curves.push({
24095
+ startX: rightBottom.endX,
24096
+ startY: rightBottom.endY,
24097
+ controlX: right,
24098
+ controlY: bottom,
24099
+ endX: rightSide.endX,
24100
+ endY: rightSide.endY,
24101
+ clipRect: rightSide.clipRect
24102
+ });
24103
+ }
24104
+ return [...rounded, ...curves];
24105
+ }
24106
+ function nearlyEqual(left, right) {
24107
+ return Math.abs(left - right) < 1e-3;
24108
+ }
24109
+ function resolveRangeBorderSegments(descriptors, resolveClipRect) {
24110
+ const byLeft = groupDescriptorsByCoordinate(
24111
+ descriptors,
24112
+ (descriptor) => descriptor.rect.x
24113
+ );
24114
+ const byRight = groupDescriptorsByCoordinate(
24115
+ descriptors,
24116
+ (descriptor) => descriptor.rect.x + descriptor.rect.width
24117
+ );
24118
+ const byTop = groupDescriptorsByCoordinate(
24119
+ descriptors,
24120
+ (descriptor) => descriptor.rect.y
24121
+ );
24122
+ const byBottom = groupDescriptorsByCoordinate(
24123
+ descriptors,
24124
+ (descriptor) => descriptor.rect.y + descriptor.rect.height
24125
+ );
24126
+ return descriptors.flatMap((descriptor) => {
24127
+ const { rect } = descriptor;
24128
+ const left = rect.x;
24129
+ const right = rect.x + rect.width;
24130
+ const top = rect.y;
24131
+ const bottom = rect.y + rect.height;
24132
+ const clipRect = resolveClipRect(descriptor);
24133
+ const horizontal = (y, side) => {
24134
+ const adjacent = (side === "top" ? byBottom : byTop).get(
24135
+ coordinateKey(side === "top" ? top : bottom)
24136
+ ) ?? [];
24137
+ return subtractCoveredIntervals(
24138
+ left,
24139
+ right,
24140
+ adjacent.flatMap((other) => {
24141
+ if (other === descriptor) return [];
24142
+ return [[other.rect.x, other.rect.x + other.rect.width]];
24143
+ })
24144
+ ).map(([start, end]) => ({
24145
+ startX: start + (Math.abs(start - left) < 1e-3 ? 0.5 : 0),
24146
+ startY: y,
24147
+ endX: end - (Math.abs(end - right) < 1e-3 ? 0.5 : 0),
24148
+ endY: y,
24149
+ clipRect
24150
+ }));
24151
+ };
24152
+ const vertical = (x, side) => {
24153
+ const adjacent = (side === "left" ? byRight : byLeft).get(
24154
+ coordinateKey(side === "left" ? left : right)
24155
+ ) ?? [];
24156
+ return subtractCoveredIntervals(
24157
+ top,
24158
+ bottom,
24159
+ adjacent.flatMap((other) => {
24160
+ if (other === descriptor) return [];
24161
+ return [[other.rect.y, other.rect.y + other.rect.height]];
24162
+ })
24163
+ ).map(([start, end]) => ({
24164
+ startX: x,
24165
+ startY: start + (Math.abs(start - top) < 1e-3 ? 0.5 : 0),
24166
+ endX: x,
24167
+ endY: end - (Math.abs(end - bottom) < 1e-3 ? 0.5 : 0),
24168
+ clipRect
24169
+ }));
24170
+ };
24171
+ return [
24172
+ ...horizontal(top + 0.5, "top"),
24173
+ ...horizontal(bottom - 0.5, "bottom"),
24174
+ ...vertical(left + 0.5, "left"),
24175
+ ...vertical(right - 0.5, "right")
24176
+ ];
24177
+ });
24178
+ }
24179
+ function groupDescriptorsByCoordinate(descriptors, getCoordinate) {
24180
+ const groups = /* @__PURE__ */ new Map();
24181
+ descriptors.forEach((descriptor) => {
24182
+ const key = coordinateKey(getCoordinate(descriptor));
24183
+ const group = groups.get(key) ?? [];
24184
+ group.push(descriptor);
24185
+ groups.set(key, group);
24186
+ });
24187
+ return groups;
24188
+ }
24189
+ function coordinateKey(value) {
24190
+ return String(Math.round(value * 1e3) / 1e3);
24191
+ }
24192
+ function subtractCoveredIntervals(start, end, coveredIntervals) {
24193
+ let visible = [[start, end]];
24194
+ coveredIntervals.forEach(([coveredStart, coveredEnd]) => {
24195
+ visible = visible.flatMap(([currentStart, currentEnd]) => {
24196
+ const overlapStart = Math.max(currentStart, coveredStart);
24197
+ const overlapEnd = Math.min(currentEnd, coveredEnd);
24198
+ if (overlapEnd <= overlapStart) return [[currentStart, currentEnd]];
24199
+ const next = [];
24200
+ if (overlapStart > currentStart) next.push([currentStart, overlapStart]);
24201
+ if (overlapEnd < currentEnd) next.push([overlapEnd, currentEnd]);
24202
+ return next;
24203
+ });
24204
+ });
24205
+ return visible.filter(
24206
+ ([currentStart, currentEnd]) => currentEnd > currentStart
24207
+ );
23865
24208
  }
23866
24209
  function drawRangeHighlightBorder(ctx, rect, edges = {}) {
23867
24210
  ctx.save();
@@ -24124,6 +24467,7 @@ function executeListTableRenderPipeline(params) {
24124
24467
  descriptors,
24125
24468
  selection,
24126
24469
  width,
24470
+ height,
24127
24471
  headerHeight,
24128
24472
  topFrozenHeight,
24129
24473
  scrollBodyTop,
@@ -24151,7 +24495,14 @@ function executeListTableRenderPipeline(params) {
24151
24495
  descriptors,
24152
24496
  theme.borderColor,
24153
24497
  scrollbarOpacity,
24154
- isScrollbarInteractive
24498
+ isScrollbarInteractive,
24499
+ {
24500
+ top: 0,
24501
+ height,
24502
+ headerBottom: headerHeight,
24503
+ headerBackgroundColor: theme.headerBackgroundColor,
24504
+ bodyBackgroundColor: theme.backgroundColor
24505
+ }
24155
24506
  );
24156
24507
  if (headerDraggingIndicator) {
24157
24508
  drawDragOverlayFrame({
@@ -25271,7 +25622,7 @@ var ListTableScrollToController = class {
25271
25622
  });
25272
25623
  const targetTop = visibleRowIndex == null ? null : resolveScrollTopForRowIndex({
25273
25624
  rowIndex: visibleRowIndex,
25274
- rowCount: snapshot.visibleRows.length,
25625
+ rowCount: snapshot.frozenRows.scroll.dataRowIndexAligned ? snapshot.dataRowCount : snapshot.visibleRows.length,
25275
25626
  rowHeight: snapshot.rowHeight,
25276
25627
  maxScrollTop: snapshot.viewport.maxScrollTop,
25277
25628
  frozenRows: snapshot.frozenRows
@@ -26618,7 +26969,7 @@ var ListTableCore = class {
26618
26969
  */
26619
26970
  changeDensity(density) {
26620
26971
  this.headerActionController.changeTableDensity(
26621
- density === 32 ? "compact" : density === 56 ? "comfortable" : "middle"
26972
+ density === "auto" ? "auto" : density === 32 ? "compact" : density === 56 ? "comfortable" : "middle"
26622
26973
  );
26623
26974
  }
26624
26975
  /**