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