@canvas-components/list-table 0.3.2 → 0.3.3

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
@@ -335,6 +335,30 @@ function stretchColumnWidths(columns, containerWidth) {
335
335
  stretchableColumns[stretchableColumns.length - 1].width += remain;
336
336
  }
337
337
  }
338
+ function shrinkColumnWidthsToFit(columns, containerWidth) {
339
+ let remaining = Math.max(
340
+ Math.ceil(computeColumnWidths(columns) - containerWidth),
341
+ 0
342
+ );
343
+ let shrinkableColumns = columns.filter(
344
+ (column) => column.width > column.minWidth
345
+ );
346
+ while (remaining > 0 && shrinkableColumns.length > 0) {
347
+ const share = Math.max(Math.floor(remaining / shrinkableColumns.length), 1);
348
+ shrinkableColumns.forEach((column) => {
349
+ if (remaining <= 0) {
350
+ return;
351
+ }
352
+ const shrink = Math.min(column.width - column.minWidth, share, remaining);
353
+ column.width -= shrink;
354
+ remaining -= shrink;
355
+ });
356
+ shrinkableColumns = shrinkableColumns.filter(
357
+ (column) => column.width > column.minWidth
358
+ );
359
+ }
360
+ return remaining === 0;
361
+ }
338
362
 
339
363
  // src/domain/columns/flatten-leaf-columns.ts
340
364
  function flattenLeafColumns(columns) {
@@ -3218,7 +3242,7 @@ function drawBodyButtonContent(params) {
3218
3242
  const top = rect.y + (rect.height - height) / 2;
3219
3243
  const palette = resolveButtonPalette(content);
3220
3244
  const textIndent = resolveContentTextIndent(content);
3221
- const paddingInline = BUTTON_PADDING_INLINE_MAP[size];
3245
+ const paddingInline = resolveButtonPaddingInline(content, size);
3222
3246
  const radius = BUTTON_RADIUS_MAP[size];
3223
3247
  ctx.save();
3224
3248
  ctx.globalAlpha *= resolveContentOpacity(content);
@@ -3326,9 +3350,12 @@ function measureButtonContentWidth(ctx, content, theme) {
3326
3350
  const intrinsicWidth = Math.max(
3327
3351
  ctx.measureText(content.text).width + resolveContentTextIndent(content),
3328
3352
  0
3329
- ) + BUTTON_PADDING_INLINE_MAP[size] * 2;
3353
+ ) + resolveButtonPaddingInline(content, size) * 2;
3330
3354
  return resolveContentLayoutWidth(content, intrinsicWidth);
3331
3355
  }
3356
+ function resolveButtonPaddingInline(content, size) {
3357
+ return content.buttonType === "link" || content.buttonType === "text" ? 4 : BUTTON_PADDING_INLINE_MAP[size];
3358
+ }
3332
3359
  function measureButtonContentHeight(content) {
3333
3360
  return BUTTON_HEIGHT_MAP[resolveButtonSize(content.size)];
3334
3361
  }
@@ -6855,7 +6882,7 @@ function expandBodyContents(contents) {
6855
6882
  expanded.push({
6856
6883
  content,
6857
6884
  contentIndex,
6858
- gapBefore: expanded.length === 0 || textOnly ? 0 : previousContent?.type === "link" && content.type === "link" ? LINK_CONTENT_GAP : CONTENT_GAP
6885
+ gapBefore: expanded.length === 0 || textOnly ? 0 : resolveInlineContentGap(previousContent, content)
6859
6886
  });
6860
6887
  if ((content.type === "checkbox" || content.type === "radio") && content.label) {
6861
6888
  const textLabelContent = {
@@ -6874,6 +6901,12 @@ function expandBodyContents(contents) {
6874
6901
  });
6875
6902
  return expanded;
6876
6903
  }
6904
+ function resolveInlineContentGap(previous, current) {
6905
+ return isInlineActionContent(previous) && isInlineActionContent(current) ? LINK_CONTENT_GAP : CONTENT_GAP;
6906
+ }
6907
+ function isInlineActionContent(content) {
6908
+ return content?.type === "link" || content?.type === "button" && (content.buttonType === "link" || content.buttonType === "text");
6909
+ }
6877
6910
  function buildSingleLineLayout(ctx, contents, availableWidth, theme) {
6878
6911
  const line = {
6879
6912
  items: [],
@@ -10463,7 +10496,7 @@ var ListTableCarouselController = class {
10463
10496
  var SUMMARY_ASYNC_BATCH_SIZE = 2e3;
10464
10497
  var SUMMARY_ASYNC_FRAME_BUDGET = 8;
10465
10498
  async function computeSummaryValuesAsync(params) {
10466
- const { rows, columns, signal } = params;
10499
+ const { rows, columns, mergeCell, signal } = params;
10467
10500
  const summaryValues = /* @__PURE__ */ new Map();
10468
10501
  const accumulators = [];
10469
10502
  columns.forEach((column) => {
@@ -10516,8 +10549,14 @@ async function computeSummaryValuesAsync(params) {
10516
10549
  }
10517
10550
  startIndex = endIndex;
10518
10551
  }
10552
+ const mergedRowCount = accumulators.some(
10553
+ (item) => item.type === "mergedRowCount"
10554
+ ) ? countMergedRows(rows, columns, mergeCell) : null;
10519
10555
  accumulators.forEach((item) => {
10520
- summaryValues.set(item.column.key, finalizeSummaryValue(item, rows));
10556
+ summaryValues.set(
10557
+ item.column.key,
10558
+ finalizeSummaryValue(item, rows, mergedRowCount)
10559
+ );
10521
10560
  });
10522
10561
  return summaryValues;
10523
10562
  }
@@ -10572,7 +10611,7 @@ function updateSummaryAccumulator(item, record) {
10572
10611
  item.max = numericValue;
10573
10612
  }
10574
10613
  }
10575
- function finalizeSummaryValue(item, rows) {
10614
+ function finalizeSummaryValue(item, rows, mergedRowCount) {
10576
10615
  if (item.column.summaryTitle != null) {
10577
10616
  return item.column.summaryTitle;
10578
10617
  }
@@ -10580,7 +10619,11 @@ function finalizeSummaryValue(item, rows) {
10580
10619
  return formatSummaryOutput(item, String(rows.length), rows);
10581
10620
  }
10582
10621
  if (item.type === "mergedRowCount") {
10583
- return formatSummaryOutput(item, String(countMergedRows(rows)), rows);
10622
+ return formatSummaryOutput(
10623
+ item,
10624
+ String(mergedRowCount ?? rows.length),
10625
+ rows
10626
+ );
10584
10627
  }
10585
10628
  if (item.type === "count") {
10586
10629
  return formatSummaryOutput(item, String(item.valueCount), rows);
@@ -10671,7 +10714,76 @@ function formatSummaryOutput(item, value, rows) {
10671
10714
  }
10672
10715
  return value;
10673
10716
  }
10674
- function countMergedRows(rows) {
10717
+ function countMergedRows(rows, columns, mergeCell) {
10718
+ const coveredRowIndexes = /* @__PURE__ */ new Set();
10719
+ const explicitRowSpans = /* @__PURE__ */ new Map();
10720
+ columns.forEach((column) => {
10721
+ if (!column.onCell) {
10722
+ return;
10723
+ }
10724
+ rows.forEach((record, rowIndex) => {
10725
+ const value = utils.getValueByDataIndex(record, column.dataIndex);
10726
+ const span = column.onCell?.(value, record, rowIndex, column);
10727
+ if (!span || !Object.prototype.hasOwnProperty.call(span, "rowSpan")) {
10728
+ return;
10729
+ }
10730
+ const rowSpan = span.rowSpan ?? 1;
10731
+ explicitRowSpans.set(`${rowIndex}::${column.key}`, rowSpan);
10732
+ if (rowSpan === 0) {
10733
+ coveredRowIndexes.add(rowIndex);
10734
+ return;
10735
+ }
10736
+ if (!Number.isFinite(rowSpan) || rowSpan <= 1) {
10737
+ return;
10738
+ }
10739
+ const spanEnd = Math.min(
10740
+ rows.length,
10741
+ rowIndex + Math.floor(rowSpan)
10742
+ );
10743
+ for (let index = rowIndex + 1; index < spanEnd; index += 1) {
10744
+ coveredRowIndexes.add(index);
10745
+ }
10746
+ });
10747
+ });
10748
+ const rowMergeRule = mergeCell?.row;
10749
+ const targetDataIndexes = rowMergeRule?.columns?.length ? rowMergeRule.columns : rowMergeRule?.keys;
10750
+ const targetMergeColumns = columns.filter(
10751
+ (column) => targetDataIndexes?.some(
10752
+ (dataIndex) => utils.isSameDataIndex(column.dataIndex, dataIndex)
10753
+ )
10754
+ );
10755
+ if (rowMergeRule?.keys.length && targetMergeColumns.length) {
10756
+ targetMergeColumns.forEach((column) => {
10757
+ let rowIndex = 0;
10758
+ while (rowIndex < rows.length) {
10759
+ if (explicitRowSpans.has(`${rowIndex}::${column.key}`)) {
10760
+ rowIndex += 1;
10761
+ continue;
10762
+ }
10763
+ const currentGroupKey = getMergeGroupKey(
10764
+ rows[rowIndex],
10765
+ rowMergeRule.keys
10766
+ );
10767
+ let rowSpan = 1;
10768
+ for (let index = rowIndex + 1; index < rows.length; index += 1) {
10769
+ if (explicitRowSpans.has(`${index}::${column.key}`)) {
10770
+ break;
10771
+ }
10772
+ if (getMergeGroupKey(rows[index], rowMergeRule.keys) !== currentGroupKey) {
10773
+ break;
10774
+ }
10775
+ rowSpan += 1;
10776
+ }
10777
+ for (let index = rowIndex + 1; index < rowIndex + rowSpan; index += 1) {
10778
+ coveredRowIndexes.add(index);
10779
+ }
10780
+ rowIndex += rowSpan;
10781
+ }
10782
+ });
10783
+ }
10784
+ if (coveredRowIndexes.size > 0) {
10785
+ return rows.length - coveredRowIndexes.size;
10786
+ }
10675
10787
  return rows.reduce((count, record) => {
10676
10788
  if (record == null || typeof record !== "object") {
10677
10789
  return count + 1;
@@ -10683,6 +10795,20 @@ function countMergedRows(rows) {
10683
10795
  return rowSpan > 0 ? count + 1 : count;
10684
10796
  }, 0);
10685
10797
  }
10798
+ function getMergeGroupKey(record, keys) {
10799
+ return keys.map(
10800
+ (dataIndex) => normalizeMergeValue(utils.getValueByDataIndex(record, dataIndex))
10801
+ ).join("|");
10802
+ }
10803
+ function normalizeMergeValue(value) {
10804
+ if (value == null) {
10805
+ return "";
10806
+ }
10807
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
10808
+ return String(value);
10809
+ }
10810
+ return JSON.stringify(value) ?? "";
10811
+ }
10686
10812
  function yieldToMainThread() {
10687
10813
  return new Promise((resolve) => {
10688
10814
  if (typeof requestAnimationFrame === "function") {
@@ -20191,6 +20317,10 @@ function buildListTableRenderSnapshot(params) {
20191
20317
  groupedColumnKeys
20192
20318
  );
20193
20319
  const leafColumns = flattenLeafColumns(normalizedColumns);
20320
+ const totalColumnWidth = computeColumnWidths(leafColumns);
20321
+ if (width > 0 && totalColumnWidth > width && totalColumnWidth <= hostWidth) {
20322
+ shrinkColumnWidthsToFit(leafColumns, width);
20323
+ }
20194
20324
  if (options.stretchColumns !== false && width > 0 && !draggingResize) {
20195
20325
  stretchColumnWidths(leafColumns, width);
20196
20326
  }
@@ -20734,8 +20864,8 @@ function updateListTableRenderSnapshotScroll(params) {
20734
20864
  } : snapshot.frozenRows;
20735
20865
  return {
20736
20866
  ...snapshot,
20737
- width,
20738
- height,
20867
+ width: snapshot.width,
20868
+ height: snapshot.height,
20739
20869
  columnSegments,
20740
20870
  headerRows,
20741
20871
  scrollbarLayout,
@@ -21120,13 +21250,8 @@ function drawScrollbars(ctx, layout, descriptors, borderColor, opacity = 1, inte
21120
21250
  verticalFrame.bodyBackgroundColor
21121
21251
  );
21122
21252
  }
21123
- if (layout.vertical && verticalFrame) {
21124
- drawVerticalScrollbarFrame(
21125
- ctx,
21126
- layout.vertical,
21127
- verticalFrame,
21128
- borderColor
21129
- );
21253
+ if (verticalFrame) {
21254
+ drawVerticalScrollbarFrame(ctx, verticalFrame, borderColor);
21130
21255
  }
21131
21256
  if (layout.horizontal) {
21132
21257
  drawAxisScrollbar(
@@ -21244,28 +21369,28 @@ function drawTrackBorder(ctx, rect, axis, borderColor) {
21244
21369
  ctx.stroke();
21245
21370
  ctx.restore();
21246
21371
  }
21247
- function drawVerticalScrollbarFrame(ctx, layout, frame, borderColor) {
21248
- const left = Math.round(layout.decreaseButton.x) + 0.5;
21249
- const right = Math.round(layout.decreaseButton.x + layout.decreaseButton.width) - 0.5;
21372
+ function drawVerticalScrollbarFrame(ctx, frame, borderColor) {
21373
+ const left = Math.round(frame.x) + 0.5;
21374
+ const right = Math.round(frame.x + frame.width) - 0.5;
21250
21375
  const top = Math.round(frame.top) + 0.5;
21251
21376
  const bottom = Math.round(frame.top + frame.height) - 0.5;
21252
21377
  const headerBottom = Math.round(frame.headerBottom) + 0.5;
21253
- if (right <= left || bottom <= top) {
21378
+ if (frame.width <= 0 || right <= left || bottom <= top) {
21254
21379
  return;
21255
21380
  }
21256
21381
  ctx.save();
21257
21382
  ctx.fillStyle = frame.headerBackgroundColor;
21258
21383
  ctx.fillRect(
21259
- layout.decreaseButton.x,
21384
+ frame.x,
21260
21385
  frame.top,
21261
- layout.decreaseButton.width,
21386
+ frame.width,
21262
21387
  Math.max(frame.headerBottom - frame.top, 0)
21263
21388
  );
21264
21389
  ctx.fillStyle = frame.bodyBackgroundColor;
21265
21390
  ctx.fillRect(
21266
- layout.decreaseButton.x,
21391
+ frame.x,
21267
21392
  frame.headerBottom,
21268
- layout.decreaseButton.width,
21393
+ frame.width,
21269
21394
  Math.max(frame.top + frame.height - frame.headerBottom, 0)
21270
21395
  );
21271
21396
  ctx.strokeStyle = borderColor;
@@ -22111,7 +22236,7 @@ function buildAutoRowSpanMap(rows, columns, rule, spanConfigMap, sourceRowIndexM
22111
22236
  rowIndex += 1;
22112
22237
  continue;
22113
22238
  }
22114
- const currentGroupKey = getMergeGroupKey(rows[rowIndex], groupKeys);
22239
+ const currentGroupKey = getMergeGroupKey2(rows[rowIndex], groupKeys);
22115
22240
  let rowSpan = 1;
22116
22241
  for (let index = rowIndex + 1; index < rows.length; index += 1) {
22117
22242
  if (sourceRowIndexMap[index] !== (sourceRowIndexMap[index - 1] ?? index - 1) + 1) {
@@ -22121,7 +22246,7 @@ function buildAutoRowSpanMap(rows, columns, rule, spanConfigMap, sourceRowIndexM
22121
22246
  if (hasExplicitSpan(spanConfigMap.get(nextCellKey), "rowSpan")) {
22122
22247
  break;
22123
22248
  }
22124
- if (getMergeGroupKey(rows[index], groupKeys) !== currentGroupKey) {
22249
+ if (getMergeGroupKey2(rows[index], groupKeys) !== currentGroupKey) {
22125
22250
  break;
22126
22251
  }
22127
22252
  rowSpan += 1;
@@ -22224,13 +22349,13 @@ function clampSpan(span, max) {
22224
22349
  }
22225
22350
  return Math.max(1, Math.min(Math.floor(span), max));
22226
22351
  }
22227
- function getMergeGroupKey(record, keys) {
22352
+ function getMergeGroupKey2(record, keys) {
22228
22353
  if (!keys?.length) {
22229
22354
  return "";
22230
22355
  }
22231
- return keys.map((key) => normalizeMergeValue(utils.getValueByDataIndex(record, key))).join("|");
22356
+ return keys.map((key) => normalizeMergeValue2(utils.getValueByDataIndex(record, key))).join("|");
22232
22357
  }
22233
- function normalizeMergeValue(value) {
22358
+ function normalizeMergeValue2(value) {
22234
22359
  if (value == null) {
22235
22360
  return "";
22236
22361
  }
@@ -22240,7 +22365,7 @@ function normalizeMergeValue(value) {
22240
22365
  return JSON.stringify(value) ?? "";
22241
22366
  }
22242
22367
  function isSameMergeValue(left, right) {
22243
- return normalizeMergeValue(left) === normalizeMergeValue(right);
22368
+ return normalizeMergeValue2(left) === normalizeMergeValue2(right);
22244
22369
  }
22245
22370
  function getMergedCellWidth(columns, startIndex, colSpan) {
22246
22371
  let width = 0;
@@ -24503,6 +24628,11 @@ function executeListTableRenderPipeline(params) {
24503
24628
  scrollbarOpacity,
24504
24629
  isScrollbarInteractive,
24505
24630
  {
24631
+ x: width,
24632
+ width: options.scrollbar?.visible === false ? 0 : Math.max(
24633
+ options.scrollbar?.thickness ?? DEFAULT_SCROLLBAR_THICKNESS,
24634
+ 6
24635
+ ),
24506
24636
  top: 0,
24507
24637
  height,
24508
24638
  headerBottom: headerHeight,
@@ -26004,6 +26134,7 @@ var ListTableSummaryController = class {
26004
26134
  const summaryTask = computeSummaryValuesAsync({
26005
26135
  rows: snapshot.displayRows,
26006
26136
  columns: snapshot.leafColumns,
26137
+ mergeCell: this.options.getOptions().query?.mergeCell,
26007
26138
  signal
26008
26139
  }).then((summaryValues) => {
26009
26140
  if (signal.aborted || taskId !== this.summaryTaskId) {