@canvas-components/list-table 0.3.23 → 0.3.25

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/README.md CHANGED
@@ -247,6 +247,7 @@ table.mount();
247
247
  | `theme` | `Partial<ListTableTheme>` | 主题覆盖 |
248
248
  | `striped` | `boolean` | 是否开启斑马纹 |
249
249
  | `highlightMode` | `"cell" \| "row" \| "column" \| "cross"` | 点击高亮模式 |
250
+ | `keyboardNavigation` | `{ tabWrap?: boolean; verticalWrap?: boolean }` | 键盘边界导航;两项默认均为 `true` |
250
251
  | `contextMenu` | `false \| ListTableContextMenuOptions` | 右键菜单配置 |
251
252
  | `grouping` | `ListTableGroupingOptions` | 分组栏、初始分组列与变化回调 |
252
253
  | `rowHeight` | `number \| "auto"` | 行高 |
@@ -268,6 +269,8 @@ table.mount();
268
269
  | `rowDrag` | `ListTableRowDragOptions` | 行拖拽配置 |
269
270
  | `debug` | `ListTableDebugOptions` | 调试配置 |
270
271
 
272
+ `keyboardNavigation.tabWrap` 控制 Tab / Shift+Tab 在行尾 / 行首是否进入相邻行;`verticalWrap` 控制 ↑ / ↓ 在列首 / 列尾是否进入相邻列。设为 `false` 时到对应边界即停止,不改变当前活动单元格。
273
+
271
274
  ### 分批加载与服务端汇总
272
275
 
273
276
  数据仍在异步生成或分批加载时,设置表格顶层属性 `loading: true`。此时汇总行及标题正常显示,统计结果保持空白,也不会计算首批临时数据。完整数据就绪后,将完整 `dataSource` 与 `loading: false` 一起更新,表格自动计算汇总并在完成后统一显示结果。默认值为 `false`,正常的空数据仍可汇总为零。
package/dist/index.cjs CHANGED
@@ -2134,7 +2134,7 @@ function createEmptySelection() {
2134
2134
  };
2135
2135
  }
2136
2136
  function resolveAdjacentCellSelection(params) {
2137
- const { selection, rowCount, columnKeys, direction } = params;
2137
+ const { selection, rowCount, columnKeys, direction, verticalWrap = true } = params;
2138
2138
  if (selection.rowIndex == null || selection.columnKey == null || selection.rowIndex < 0 || selection.rowIndex >= rowCount) {
2139
2139
  return null;
2140
2140
  }
@@ -2143,6 +2143,10 @@ function resolveAdjacentCellSelection(params) {
2143
2143
  return null;
2144
2144
  }
2145
2145
  if (direction === "up" || direction === "down") {
2146
+ const nextRowIndex = selection.rowIndex + (direction === "up" ? -1 : 1);
2147
+ if (!verticalWrap) {
2148
+ return nextRowIndex < 0 || nextRowIndex >= rowCount ? null : { rowIndex: nextRowIndex, columnKey: selection.columnKey };
2149
+ }
2146
2150
  const flatIndex = columnIndex * rowCount + selection.rowIndex;
2147
2151
  const nextFlatIndex = flatIndex + (direction === "up" ? -1 : 1);
2148
2152
  const cellCount = rowCount * columnKeys.length;
@@ -2165,7 +2169,7 @@ function resolveAdjacentCellSelection(params) {
2165
2169
  };
2166
2170
  }
2167
2171
  function resolveTabCellSelection(params) {
2168
- const { selection, rowCount, columnKeys, reverse = false } = params;
2172
+ const { selection, rowCount, columnKeys, reverse = false, tabWrap = true } = params;
2169
2173
  if (selection.rowIndex == null || selection.columnKey == null || selection.rowIndex < 0 || selection.rowIndex >= rowCount || columnKeys.length === 0) {
2170
2174
  return null;
2171
2175
  }
@@ -2173,6 +2177,13 @@ function resolveTabCellSelection(params) {
2173
2177
  if (columnIndex < 0) {
2174
2178
  return null;
2175
2179
  }
2180
+ if (!tabWrap) {
2181
+ const nextColumnIndex = columnIndex + (reverse ? -1 : 1);
2182
+ return nextColumnIndex < 0 || nextColumnIndex >= columnKeys.length ? null : {
2183
+ rowIndex: selection.rowIndex,
2184
+ columnKey: columnKeys[nextColumnIndex]
2185
+ };
2186
+ }
2176
2187
  const flatIndex = selection.rowIndex * columnKeys.length + columnIndex;
2177
2188
  const nextFlatIndex = flatIndex + (reverse ? -1 : 1);
2178
2189
  const cellCount = rowCount * columnKeys.length;
@@ -8711,6 +8722,7 @@ function drawHeaderCell(params, cell, clipRect) {
8711
8722
  rect: getHeaderSelectionRect(rect),
8712
8723
  columnKey: cell.node.key,
8713
8724
  controlType: params.rowSelection.type,
8725
+ cursor: params.rowSelection.disabled ? "not-allowed" : "pointer",
8714
8726
  fixed: cell.node.fixed
8715
8727
  });
8716
8728
  }
@@ -8900,6 +8912,7 @@ function drawHeaderActions(params, rect, columnKey, visibilityState, fixed, visi
8900
8912
  rect: hitRect,
8901
8913
  columnKey,
8902
8914
  actionType,
8915
+ cursor: "pointer",
8903
8916
  visibilityState,
8904
8917
  fixed
8905
8918
  });
@@ -11099,7 +11112,7 @@ function drawBodySelectionContent(params) {
11099
11112
  controlType: content.type,
11100
11113
  contentIndex,
11101
11114
  contentKey: content.key,
11102
- cursor: content.disabled === true ? "not-allowed" : content.cursor ?? (content.onClick ? "pointer" : void 0)
11115
+ cursor: content.disabled === true ? "not-allowed" : content.cursor ?? (content.onClick || column.key === ROW_SELECTION_COLUMN_KEY ? "pointer" : void 0)
11103
11116
  });
11104
11117
  return controlRect.width;
11105
11118
  }
@@ -11115,7 +11128,14 @@ function drawSelectionControl(ctx, rect, type, checked, disabled, indeterminate
11115
11128
  ctx.fillStyle = fillColor;
11116
11129
  ctx.strokeStyle = strokeColor;
11117
11130
  ctx.lineWidth = 1.5;
11118
- roundRectPath2(ctx, rect.x, rect.y, rect.width, rect.height, 4);
11131
+ roundRectPath2(
11132
+ ctx,
11133
+ rect.x + 1,
11134
+ rect.y + 1,
11135
+ Math.max(rect.width - 2, 0),
11136
+ Math.max(rect.height - 2, 0),
11137
+ 4
11138
+ );
11119
11139
  ctx.fill();
11120
11140
  ctx.stroke();
11121
11141
  if (indeterminate) {
@@ -17990,9 +18010,7 @@ async function exportAllRowsTxtContent(params) {
17990
18010
  });
17991
18011
  }
17992
18012
  async function exportAllRowsXlsxContent(params) {
17993
- const columns = params.columns.filter(
17994
- (column) => column.key !== ROW_SELECTION_COLUMN_KEY && column.key !== ROW_SELECTOR_COLUMN_KEY
17995
- );
18013
+ const columns = params.columns.filter(isExportableColumn);
17996
18014
  const footerRows = [];
17997
18015
  if (params.includeSummary) {
17998
18016
  const values = await computeSummaryValuesAsync({
@@ -18091,14 +18109,21 @@ function resolveProgressClipboardPercent(content) {
18091
18109
  return Math.min(Math.max((content.value - min) / range * 100, 0), 100);
18092
18110
  }
18093
18111
  function buildExportColumns(columns) {
18094
- return columns.filter(
18095
- (column) => column.key !== ROW_SELECTION_COLUMN_KEY && column.key !== ROW_SELECTOR_COLUMN_KEY
18096
- ).map((column) => ({
18112
+ return columns.filter(isExportableColumn).map((column) => ({
18097
18113
  key: column.key,
18098
18114
  title: column.title ?? column.key,
18099
18115
  value: (row, rowIndex) => getCellClipboardText(row, rowIndex, column)
18100
18116
  }));
18101
18117
  }
18118
+ function isExportableColumn(column) {
18119
+ if (column.key === ROW_SELECTION_COLUMN_KEY || column.key === ROW_SELECTOR_COLUMN_KEY || column.key === EXPAND_COLUMN_KEY) {
18120
+ return false;
18121
+ }
18122
+ if (column.exportable !== void 0) return column.exportable;
18123
+ return !(/^(?:action|actions|operate|operation|operations)$/i.test(column.key) || /^(?:操作|操作列|操作按钮|action|actions|operation|operations)$/i.test(
18124
+ column.title.trim()
18125
+ ));
18126
+ }
18102
18127
  function buildTableExportFileName(extension) {
18103
18128
  const now2 = /* @__PURE__ */ new Date();
18104
18129
  const stamp = [
@@ -18274,13 +18299,14 @@ var ListTableContentActionController = class {
18274
18299
  * 异步导出全部原始数据为 XLSX。
18275
18300
  */
18276
18301
  exportXlsx(options) {
18302
+ const includeSummary = options?.includeSummary ?? this.options.getSummaryVisible?.() ?? false;
18277
18303
  options = { ...this.options.getOptions().exportOptions, ...options };
18278
18304
  this.startExportTask(
18279
18305
  (fileName) => exportAllRowsXlsxContent({
18280
18306
  rows: this.options.getOptions().dataSource,
18281
18307
  columns: this.options.getLeafColumns(),
18282
18308
  ...options,
18283
- includeSummary: options?.includeSummary ?? this.options.getSummaryVisible?.() ?? false,
18309
+ includeSummary,
18284
18310
  fileName: fileName ?? options?.fileName,
18285
18311
  onProgress: (progress) => {
18286
18312
  const fileLabel = progress.fileCount && progress.fileCount > 1 ? `\uFF08\u7B2C ${progress.fileIndex}/${progress.fileCount} \u4EFD\uFF09` : "";
@@ -19239,7 +19265,7 @@ function resolveScrollTopToRevealRow(params) {
19239
19265
  if (frozenRows.top.rowIndexMap?.includes(rowIndex) || frozenRows.bottom.rowIndexMap?.includes(rowIndex)) {
19240
19266
  return null;
19241
19267
  }
19242
- const scrollSectionIndex = frozenRows.scroll.rowIndexMap ? frozenRows.scroll.rowIndexMap.indexOf(rowIndex) : rowIndex;
19268
+ const scrollSectionIndex = frozenRows.scroll.dataRowIndexAligned ? rowIndex : frozenRows.scroll.rowIndexMap ? frozenRows.scroll.rowIndexMap.indexOf(rowIndex) : rowIndex;
19243
19269
  if (scrollSectionIndex < 0) {
19244
19270
  return null;
19245
19271
  }
@@ -19482,7 +19508,7 @@ var ListTableEditingController = class {
19482
19508
  });
19483
19509
  const nextTop = resolveScrollTopToRevealRow({
19484
19510
  rowIndex,
19485
- rowCount: snapshot.visibleRows.length,
19511
+ rowCount: snapshot.frozenRows.scroll.dataRowIndexAligned ? snapshot.dataRowCount : snapshot.visibleRows.length,
19486
19512
  rowHeight: snapshot.rowHeight,
19487
19513
  bodyHeight: snapshot.bodyLayout.scrollBodyHeight,
19488
19514
  scrollTop: scroll.top,
@@ -20187,6 +20213,7 @@ function drawSegmentRows(params, segment, columns, startRowIndex, endRowIndex, r
20187
20213
  kind: "body",
20188
20214
  rect,
20189
20215
  columnKey: cell.column.key,
20216
+ cursor: cell.column.key === ROW_SELECTOR_COLUMN_KEY ? "pointer" : void 0,
20190
20217
  rowIndex: cell.sourceRowIndex,
20191
20218
  rowSpan: cell.rowSpan,
20192
20219
  fixed: cell.column.fixed,
@@ -28463,11 +28490,19 @@ var ListTableEventController = class {
28463
28490
  rowCount: this.host.getDisplayData().length,
28464
28491
  columnKeys: this.host.leafColumns.filter((column) => !isSystemColumnKey(column.key)).map((column) => column.key)
28465
28492
  };
28466
- const target = direction ? resolveAdjacentCellSelection({ ...navigationParams, direction }) : resolveTabCellSelection({
28493
+ const target = direction ? resolveAdjacentCellSelection({
28467
28494
  ...navigationParams,
28468
- reverse: event.shiftKey
28495
+ direction,
28496
+ verticalWrap: this.host.options.keyboardNavigation?.verticalWrap
28497
+ }) : resolveTabCellSelection({
28498
+ ...navigationParams,
28499
+ reverse: event.shiftKey,
28500
+ tabWrap: this.host.options.keyboardNavigation?.tabWrap
28469
28501
  });
28470
28502
  if (!target) {
28503
+ if (event.key === "Tab" && this.host.options.keyboardNavigation?.tabWrap === false) {
28504
+ event.preventDefault();
28505
+ }
28471
28506
  return;
28472
28507
  }
28473
28508
  event.preventDefault();