@lensui/lens-table 0.1.6 → 0.1.7
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 +93 -4
- package/dist/index.cjs +107 -13
- package/dist/index.d.cts +43 -7
- package/dist/index.d.ts +43 -7
- package/dist/index.js +108 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -104,12 +104,12 @@ export function Example() {
|
|
|
104
104
|
| `virtualized` | `boolean \| { enabled?: boolean; overscan?: number }` | `true` | 虚拟渲染配置。传`false` 时渲染全部行列;传对象时可通过 `enabled` 开关,并用 `overscan` 配置可见范围外的缓冲行列数量,默认 `4`。 |
|
|
105
105
|
| `tooltip` | `boolean \| { header?: boolean; cell?: boolean }` | `true` | 文本 tooltip 总配置。传`true` 时表头和单元格 hover 都显示完整文本;传 `false` 可关闭;传对象可分别控制表头和单元格。 |
|
|
106
106
|
| `summary` | `boolean \| { position?: 'top' \| 'bottom'; verticalBordered?: boolean; emptyValue?: ReactNode }` | `false` | 表格级合计行配置。默认不显示;传 `true` 或对象即开启合计行,对象可控制显示在表头下方或底部、是否显示内部竖线,以及无合计值单元格的填充内容。 |
|
|
107
|
-
| `rowNumber` | `boolean` | `true` | 是否显示序号列。默认开启并自动生成左侧序号列,不需要在`columns` 中配置;传 `false`
|
|
107
|
+
| `rowNumber` | `boolean \| TableRowNumberConfig` | `true` | 是否显示序号列。默认开启并自动生成左侧序号列,不需要在`columns` 中配置;传 `false` 可关闭。传 `{ fixed: false }` 可取消序号列固定,`fixed` 默认 `true`。 |
|
|
108
108
|
| `selectedCell` | `GridSelectionTarget \| null` | 非受控 | 受控单元格选中状态。传 `columnKey`,行可使用 `rowKey` 或 `rowIndex` 定位。 |
|
|
109
109
|
| `defaultSelectedCell` | `GridSelectionTarget \| null` | `null` | 默认选中单元格。传 `columnKey`,行可使用 `rowKey` 或 `rowIndex` 定位。 |
|
|
110
110
|
| `onSelectedCellChange` | `(selection) => void` | - | 单元格选中变化回调,`selection.value` 为当前单元格的原始值。 |
|
|
111
111
|
| `rangeSelection` | `boolean` | `false` | 是否允许鼠标拖动选择多个单元格。开启后支持范围复制、范围右键菜单和右下角拖拽扩展范围。 |
|
|
112
|
-
| `rowSelection` | `boolean \|
|
|
112
|
+
| `rowSelection` | `boolean \| RowSelectionConfig` | `false` | 开启行选择。可传`{ mode: 'single' \| 'multiple', showCheckbox: false }` 隐藏选择框并通过点击数据单元格选择行;默认显示选择框。默认自动生成左侧选择列,不需要在 `columns` 中配置。 |
|
|
113
113
|
| `selectedRowKeys` | `GridKey[]` | 非受控 | 受控行选择 key 列表。 |
|
|
114
114
|
| `defaultSelectedRowKeys` | `GridKey[]` | `[]` | 非受控模式下默认选中的行 key。 |
|
|
115
115
|
| `onSelectedRowChange` | `(keys, rows, indices) => void` | - | 行选择变化回调。 |
|
|
@@ -128,6 +128,8 @@ export function Example() {
|
|
|
128
128
|
| `onSortChange` | `(rows, state) => Row[]` | - | 自定义排序方法。排序状态由组件内部管理;返回排序后的行。 |
|
|
129
129
|
| `onFilterChange` | `(rows, values) => Row[]` | - | 自定义筛选方法。筛选值由组件内部管理;返回符合条件的行。 |
|
|
130
130
|
| `onCellChange` | `(change) => void` | - | 单元格编辑提交回调。 |
|
|
131
|
+
| `onCellClick` | `(cell: TableCellContext<Row>, event: React.MouseEvent<HTMLElement>) => void` | - | 数据单元格单击回调;调用 `event.preventDefault()` 可阻止默认选择行为。 |
|
|
132
|
+
| `onCellDoubleClick` | `(cell: TableCellContext<Row>, event: React.MouseEvent<HTMLElement>) => void` | - | 数据单元格双击回调,在编辑前触发;调用 `event.preventDefault()` 可阻止进入编辑。 |
|
|
131
133
|
| `onCellContextMenu` | `(event) => void` | - | 单元格右键回调,可用于扩展自定义菜单逻辑。 |
|
|
132
134
|
| `contextMenu` | `boolean \| { header?, cell?, range? }` | `true` | `true` 开启默认右键菜单,`false` 关闭右键菜单,传对象可自定义菜单项、顺序和分割线。 |
|
|
133
135
|
| `emptyContent` | `ReactNode` | 内置空状态 | 自定义空数据内容。 |
|
|
@@ -206,7 +208,7 @@ export function Example() {
|
|
|
206
208
|
| `width` | `number` | `140` | 列宽,单位 px。最小宽度由内部布局保护。 |
|
|
207
209
|
| `fixed` | `'left' \| 'right'` | - | 固定列位置。左/右固定列会覆盖滚动列并显示阴影。 |
|
|
208
210
|
| `align` | `'left' \| 'center' \| 'right'` | `'left'` | 单元格文本和拖拽预览文本对齐方式。 |
|
|
209
|
-
| `editable` | `boolean` | `false` |
|
|
211
|
+
| `editable` | `boolean \| ((value: unknown, row: Row, rowIndex: number) => boolean)` | `false` | 是否允许双击、Enter 或右键菜单进入编辑。函数按当前单元格动态判断,提交时再次检查权限。 |
|
|
210
212
|
| `editor` | `EditorConfig` | `{ type: 'text' }` | 内置编辑器配置。详见下方编辑器表。未配置时默认使用文本编辑器。 |
|
|
211
213
|
| `sortable` | `boolean` | `true` | 表头显示排序按钮。普通数据列默认开启,传 `false` 可关闭。 |
|
|
212
214
|
| `filterable` | `boolean` | `true` | 表头显示筛选按钮。普通数据列默认开启,传 `false` 可关闭。 |
|
|
@@ -494,7 +496,7 @@ const columns: GridColumn<Row>[] = [
|
|
|
494
496
|
|
|
495
497
|
拖拽后组件会在内部维护新的行列顺序,因此排序回调不是必需的。需要持久化或同步结果时,可以通过回调直接取得排序后的 `rows` 或 `columns`。列宽调整默认开启并支持非受控使用,传 `columnResizable={false}` 可关闭。
|
|
496
498
|
|
|
497
|
-
`columnDraggable` 默认开启,普通列会自动显示表头拖拽入口。行选择和行拖拽是表格级配置:开启 `rowSelection`
|
|
499
|
+
`columnDraggable` 默认开启,普通列会自动显示表头拖拽入口。行选择和行拖拽是表格级配置:开启 `rowSelection` 后默认自动生成左侧选择列(`showCheckbox: false` 时隐藏),开启 `rowDraggable` 后自动生成左侧拖拽手柄列,不需要在 `columns` 里配置 `rowSelection` 或 `rowDragHandle`。
|
|
498
500
|
|
|
499
501
|
```tsx
|
|
500
502
|
<Table
|
|
@@ -514,6 +516,20 @@ const columns: GridColumn<Row>[] = [
|
|
|
514
516
|
/>;
|
|
515
517
|
```
|
|
516
518
|
|
|
519
|
+
隐藏选择框时不生成选择列,表头全选框也会隐藏;行选择状态、回调和右键菜单仍然可用。多选模式支持 Ctrl / Command 点击追加或取消选择,以及 Shift 点击连续选择。
|
|
520
|
+
|
|
521
|
+
```tsx
|
|
522
|
+
<Table
|
|
523
|
+
columns={columns}
|
|
524
|
+
rows={rows}
|
|
525
|
+
rowNumber={{ fixed: false }}
|
|
526
|
+
rowSelection={{ mode: 'multiple', showCheckbox: false }}
|
|
527
|
+
onSelectedRowChange={(keys, selectedRows) => console.log(keys, selectedRows)}
|
|
528
|
+
/>
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
`rowNumber={true}` 或 `rowNumber={{ fixed: true }}` 固定序号列;`rowNumber={false}` 隐藏序号列。
|
|
532
|
+
|
|
517
533
|
## 虚拟渲染
|
|
518
534
|
|
|
519
535
|
默认开启虚拟渲染,只绘制可见区域和少量缓冲区域。缓冲数量默认是 `4`,可以通过对象形式调整。
|
|
@@ -693,3 +709,76 @@ pnpm check
|
|
|
693
709
|
## License
|
|
694
710
|
|
|
695
711
|
MIT
|
|
712
|
+
|
|
713
|
+
## 单元格事件与动态编辑权限
|
|
714
|
+
|
|
715
|
+
```tsx
|
|
716
|
+
const columns: TableColumn<MyRow>[] = [
|
|
717
|
+
{
|
|
718
|
+
key: 'name',
|
|
719
|
+
title: '姓名',
|
|
720
|
+
dataIndex: 'name',
|
|
721
|
+
editable: (_value, row, _rowIndex) => row.status === 'draft',
|
|
722
|
+
},
|
|
723
|
+
];
|
|
724
|
+
|
|
725
|
+
<Table
|
|
726
|
+
columns={columns}
|
|
727
|
+
rows={rows}
|
|
728
|
+
onCellClick={(cell, event) => {
|
|
729
|
+
console.log(cell.row, cell.column, cell.value, cell.rowIndex, cell.columnIndex);
|
|
730
|
+
}}
|
|
731
|
+
onCellDoubleClick={(cell, event) => {
|
|
732
|
+
console.log(cell.rowKey, cell.columnKey);
|
|
733
|
+
// event.preventDefault(); // 阻止本次双击进入编辑
|
|
734
|
+
}}
|
|
735
|
+
/>
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
事件只针对数据单元格,表头、序号列、选择列和拖拽手柄不触发;只读单元格也会触发。双击时先触发一次单击回调,再触发双击回调,不延迟单击。合并单元格返回其起始单元格,索引基于当前显示顺序,`columnIndex` 包含工具列。
|
|
739
|
+
|
|
740
|
+
`editable` 保持兼容布尔值;函数接收当前值、行数据和当前行索引,返回 `true` 才允许编辑。编辑期间权限变为 `false` 时,提交会关闭编辑器并丢弃草稿,不触发 `onCellChange`。
|
|
741
|
+
|
|
742
|
+
## Ref 方法
|
|
743
|
+
|
|
744
|
+
支持 React 18+ 的对象 ref 和回调 ref,保留行数据的泛型推导;`VelocityGrid` 别名同样支持。可导入 `TableRef<Row>`(或 `VelocityGridRef<Row>`)。
|
|
745
|
+
|
|
746
|
+
```tsx
|
|
747
|
+
import { useRef } from 'react';
|
|
748
|
+
import { Table, type TableRef } from '@lensui/lens-table';
|
|
749
|
+
|
|
750
|
+
function Example() {
|
|
751
|
+
const tableRef = useRef<TableRef<MyRow>>(null);
|
|
752
|
+
return (
|
|
753
|
+
<>
|
|
754
|
+
<button onClick={() => tableRef.current?.scrollToCell({ rowKey: 1, columnKey: 'name' })}>
|
|
755
|
+
定位
|
|
756
|
+
</button>
|
|
757
|
+
<button onClick={() => tableRef.current?.startEdit({ rowKey: 1, columnKey: 'name' })}>
|
|
758
|
+
编辑
|
|
759
|
+
</button>
|
|
760
|
+
<Table ref={tableRef} columns={columns} rows={rows} rowSelection />
|
|
761
|
+
</>
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
| 方法 | 说明 |
|
|
767
|
+
| --- | --- |
|
|
768
|
+
| `focus()` | 聚焦表格,启用键盘操作。 |
|
|
769
|
+
| `scrollToCell(target)` | 将目标数据单元格滚入可见区域,不改变选择;目标不存在时返回 `false`。 |
|
|
770
|
+
| `getSelectedCell()` | 返回当前单元格的 `TableCellContext<Row>`,未选择时返回 `null`。 |
|
|
771
|
+
| `setSelectedCell(target \| null)` | 设置或清除单元格选择,同时清除范围选择;无效目标返回 `false` 并保留原选择。 |
|
|
772
|
+
| `getSelectedRowKeys()` | 返回所选行 key 的数组副本。 |
|
|
773
|
+
| `getSelectedRows()` | 返回当前筛选和排序结果中选中的行数据,按显示顺序排列。 |
|
|
774
|
+
| `setSelectedRowKeys(keys)` | 设置行选择并触发现有回调;需要开启 `rowSelection`,单选模式只取第一个 key。 |
|
|
775
|
+
| `getSelectedColumnKeys()` | 返回所选列 key 的数组副本。 |
|
|
776
|
+
| `setSelectedColumnKeys(keys)` | 设置数据列选择,忽略无效列;需要开启 `columnSelection`,单选模式只取第一个有效 key。 |
|
|
777
|
+
| `clearSelection()` | 清空单元格、范围、行和列选择,并取消编辑。 |
|
|
778
|
+
| `startEdit(target?)` | 选择并编辑目标单元格;省略参数时编辑当前选择。目标无效或 `editable` 不允许时返回 `false`。 |
|
|
779
|
+
| `commitEdit()` | 提交当前草稿并关闭编辑器,遵循 `editable` 动态权限和 `onCellChange`。 |
|
|
780
|
+
| `cancelEdit()` | 丢弃当前草稿并关闭编辑器。 |
|
|
781
|
+
|
|
782
|
+
`target` 使用 `{ rowKey, columnKey }` 或 `{ rowIndex, columnKey }`;`rowKey` 优先,`rowIndex` 为当前显示顺序中的零基索引。工具列不能作为目标;合并单元格自动定位到起始单元格。
|
|
783
|
+
|
|
784
|
+
选择方法遵守受控/非受控约定:传入 `selectedCell`、`selectedRowKeys` 或 `selectedColumnKeys` 后,需要在相应回调中更新这些 props。尤其是受控单元格选择下的 `startEdit`,外部需要接受新的选择才能保持编辑器打开。读取方法反映最近一次 React 渲染完成后的状态,不保证在调用设置方法的同一同步代码段内立即更新;返回的行和列对象是原数据引用。
|
package/dist/index.cjs
CHANGED
|
@@ -1522,7 +1522,7 @@ function resolveContextMenuSection(section, defaults) {
|
|
|
1522
1522
|
}
|
|
1523
1523
|
return defaults;
|
|
1524
1524
|
}
|
|
1525
|
-
function
|
|
1525
|
+
function TableInner({
|
|
1526
1526
|
columns: columnProps,
|
|
1527
1527
|
rows: sourceRows,
|
|
1528
1528
|
rowKey,
|
|
@@ -1568,13 +1568,15 @@ function Table({
|
|
|
1568
1568
|
onSortChange,
|
|
1569
1569
|
onFilterChange,
|
|
1570
1570
|
onCellChange,
|
|
1571
|
+
onCellClick,
|
|
1572
|
+
onCellDoubleClick,
|
|
1571
1573
|
onCellContextMenu,
|
|
1572
1574
|
contextMenu: contextMenuConfig = true,
|
|
1573
1575
|
emptyContent,
|
|
1574
1576
|
className = "",
|
|
1575
1577
|
style,
|
|
1576
1578
|
ariaLabel = "Data grid"
|
|
1577
|
-
}) {
|
|
1579
|
+
}, ref) {
|
|
1578
1580
|
const [sourceColumns, setSourceColumns] = (0, import_react5.useState)(columnProps);
|
|
1579
1581
|
(0, import_react5.useEffect)(() => {
|
|
1580
1582
|
setSourceColumns((current) => reconcileColumns(current, columnProps));
|
|
@@ -1620,6 +1622,7 @@ function Table({
|
|
|
1620
1622
|
const customContextMenuConfig = typeof contextMenuConfig === "object" ? contextMenuConfig : void 0;
|
|
1621
1623
|
const [resizedColumnWidths, setResizedColumnWidths] = (0, import_react5.useState)({});
|
|
1622
1624
|
const leafSourceColumns = (0, import_react5.useMemo)(() => flattenDataColumns(sourceColumns), [sourceColumns]);
|
|
1625
|
+
const showRowCheckbox = Boolean(rowSelection) && (typeof rowSelection !== "object" || rowSelection.showCheckbox !== false);
|
|
1623
1626
|
(0, import_react5.useEffect)(() => {
|
|
1624
1627
|
if (!isProductionRuntime() && hasNestedFixedColumns(sourceColumns)) {
|
|
1625
1628
|
console.warn("[Table] Multi-level headers only support fixed columns on top-level columns. Nested fixed values are ignored.");
|
|
@@ -1630,19 +1633,19 @@ function Table({
|
|
|
1630
1633
|
if (rowDraggable) {
|
|
1631
1634
|
utilityColumns.push({ key: "__rvg_row_drag__", title: "", width: 36, align: "center", fixed: "left", rowDragHandle: true });
|
|
1632
1635
|
}
|
|
1633
|
-
if (
|
|
1636
|
+
if (showRowCheckbox) {
|
|
1634
1637
|
utilityColumns.push({ key: "__rvg_row_selection__", title: "", width: 44, align: "center", fixed: "left", rowSelection: true });
|
|
1635
1638
|
}
|
|
1636
1639
|
if (rowNumber) {
|
|
1637
|
-
utilityColumns.push({ key: "__rvg_row_number__", title: "#", width: getRowNumberColumnWidth(sourceRows.length), align: "center", fixed: "left", rowNumber: true });
|
|
1640
|
+
utilityColumns.push({ key: "__rvg_row_number__", title: "#", width: getRowNumberColumnWidth(sourceRows.length), align: "center", fixed: typeof rowNumber === "object" && rowNumber.fixed === false ? void 0 : "left", rowNumber: true });
|
|
1638
1641
|
}
|
|
1639
1642
|
const dataColumns = leafSourceColumns.map((column) => {
|
|
1640
1643
|
const resizedWidth = resizedColumnWidths[column.key];
|
|
1641
1644
|
return resizedWidth === void 0 ? column : { ...column, width: resizedWidth };
|
|
1642
1645
|
});
|
|
1643
1646
|
return [...utilityColumns, ...dataColumns];
|
|
1644
|
-
}, [leafSourceColumns, resizedColumnWidths, rowDraggable, rowNumber,
|
|
1645
|
-
const utilityColumnCount = (rowDraggable ? 1 : 0) + (
|
|
1647
|
+
}, [leafSourceColumns, resizedColumnWidths, rowDraggable, rowNumber, showRowCheckbox, sourceRows.length]);
|
|
1648
|
+
const utilityColumnCount = (rowDraggable ? 1 : 0) + (showRowCheckbox ? 1 : 0) + (rowNumber ? 1 : 0);
|
|
1646
1649
|
const headerCells = (0, import_react5.useMemo)(() => buildHeaderCells(sourceColumns, utilityColumnCount, headerDepth), [headerDepth, sourceColumns, utilityColumnCount]);
|
|
1647
1650
|
const activeCustomHeaderLevels = (0, import_react5.useMemo)(() => {
|
|
1648
1651
|
const levels = /* @__PURE__ */ new Map();
|
|
@@ -3348,9 +3351,15 @@ function Table({
|
|
|
3348
3351
|
scrollRef.current = { left: scroller.scrollLeft, top: scroller.scrollTop };
|
|
3349
3352
|
scheduleDraw();
|
|
3350
3353
|
}, [bodyTop, columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, scheduleDraw, viewport.width]);
|
|
3354
|
+
const isCellEditable = (0, import_react5.useCallback)((cell) => {
|
|
3355
|
+
const column = columns[cell.columnIndex];
|
|
3356
|
+
const row = rows[cell.rowIndex];
|
|
3357
|
+
if (!column || !row || column.dataIndex === void 0 || column.rowNumber || column.rowSelection || column.rowDragHandle) return false;
|
|
3358
|
+
return typeof column.editable === "function" ? column.editable(row[column.dataIndex], row, cell.rowIndex) : column.editable === true;
|
|
3359
|
+
}, [columns, rows]);
|
|
3351
3360
|
const beginEdit = (0, import_react5.useCallback)((cell) => {
|
|
3352
3361
|
const column = columns[cell.columnIndex];
|
|
3353
|
-
if (!
|
|
3362
|
+
if (!isCellEditable(cell) || column.dataIndex === void 0) return;
|
|
3354
3363
|
const value = rows[cell.rowIndex]?.[column.dataIndex];
|
|
3355
3364
|
setDraft(value == null ? "" : String(value));
|
|
3356
3365
|
const scroller = scrollerRef.current;
|
|
@@ -3392,7 +3401,7 @@ function Table({
|
|
|
3392
3401
|
return;
|
|
3393
3402
|
}
|
|
3394
3403
|
setEditing(cell);
|
|
3395
|
-
}, [columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, rows, scheduleDraw, viewport.width]);
|
|
3404
|
+
}, [columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, isCellEditable, metrics, rightFixedWidth, rowHeight, rows, scheduleDraw, viewport.width]);
|
|
3396
3405
|
const getCellEditKey = (cell) => `${typeof cell.rowKey}:${String(cell.rowKey)}\0${cell.columnKey}`;
|
|
3397
3406
|
const markCellEdited = (cell, previousValue, nextValue) => {
|
|
3398
3407
|
const key = getCellEditKey(cell);
|
|
@@ -3420,6 +3429,10 @@ function Table({
|
|
|
3420
3429
|
};
|
|
3421
3430
|
const commitEdit = (0, import_react5.useCallback)((nextDraft, close = true) => {
|
|
3422
3431
|
if (!editing) return;
|
|
3432
|
+
if (!isCellEditable(editing)) {
|
|
3433
|
+
setEditing(null);
|
|
3434
|
+
return;
|
|
3435
|
+
}
|
|
3423
3436
|
const committedDraft = nextDraft ?? draft;
|
|
3424
3437
|
const column = columns[editing.columnIndex];
|
|
3425
3438
|
const row = rows[editing.rowIndex];
|
|
@@ -3434,7 +3447,7 @@ function Table({
|
|
|
3434
3447
|
onCellChange?.({ ...editing, row, value: committedValue, previousValue });
|
|
3435
3448
|
}
|
|
3436
3449
|
if (close) setEditing(null);
|
|
3437
|
-
}, [columns, draft, editing, onCellChange, rows]);
|
|
3450
|
+
}, [columns, draft, editing, isCellEditable, onCellChange, rows]);
|
|
3438
3451
|
const renderEditor = () => {
|
|
3439
3452
|
if (!editing || !editorStyle) return null;
|
|
3440
3453
|
const column = columns[editing.columnIndex];
|
|
@@ -4336,6 +4349,77 @@ function Table({
|
|
|
4336
4349
|
`summary:${column.key}`
|
|
4337
4350
|
);
|
|
4338
4351
|
};
|
|
4352
|
+
(0, import_react5.useImperativeHandle)(ref, () => {
|
|
4353
|
+
const resolveDataCell = (target) => {
|
|
4354
|
+
const cell = resolveSelectionTarget(target);
|
|
4355
|
+
if (!cell) return null;
|
|
4356
|
+
const column = columns[cell.columnIndex];
|
|
4357
|
+
if (column.rowNumber || column.rowSelection || column.rowDragHandle) return null;
|
|
4358
|
+
const span = getCellSpan(cell.rowIndex, cell.columnIndex);
|
|
4359
|
+
if (!span) return cell;
|
|
4360
|
+
return {
|
|
4361
|
+
rowIndex: span.rowIndex,
|
|
4362
|
+
columnIndex: span.columnIndex,
|
|
4363
|
+
rowKey: getRowKey(rows[span.rowIndex], span.rowIndex),
|
|
4364
|
+
columnKey: columns[span.columnIndex].key
|
|
4365
|
+
};
|
|
4366
|
+
};
|
|
4367
|
+
return {
|
|
4368
|
+
focus: () => scrollerRef.current?.focus({ preventScroll: true }),
|
|
4369
|
+
scrollToCell: (target) => {
|
|
4370
|
+
const cell = resolveDataCell(target);
|
|
4371
|
+
if (!cell) return false;
|
|
4372
|
+
revealCell(cell);
|
|
4373
|
+
return true;
|
|
4374
|
+
},
|
|
4375
|
+
getSelectedCell: () => {
|
|
4376
|
+
if (!selection) return null;
|
|
4377
|
+
const cell = resolveDataCell(selection);
|
|
4378
|
+
if (!cell) return null;
|
|
4379
|
+
const column = columns[cell.columnIndex];
|
|
4380
|
+
const row = rows[cell.rowIndex];
|
|
4381
|
+
return { ...cell, row, column, value: column.dataIndex === void 0 ? void 0 : row[column.dataIndex] };
|
|
4382
|
+
},
|
|
4383
|
+
setSelectedCell: (target) => {
|
|
4384
|
+
const cell = target === null ? null : resolveDataCell(target);
|
|
4385
|
+
if (target !== null && !cell) return false;
|
|
4386
|
+
setSelectionRange(null);
|
|
4387
|
+
setSelection(cell);
|
|
4388
|
+
return true;
|
|
4389
|
+
},
|
|
4390
|
+
getSelectedRowKeys: () => [...rowKeys],
|
|
4391
|
+
getSelectedRows: () => rows.filter((row, index) => selectedRowKeySet.has(getRowKey(row, index))),
|
|
4392
|
+
setSelectedRowKeys: (keys) => {
|
|
4393
|
+
if (!rowSelection) return;
|
|
4394
|
+
const next = [...new Set(keys)];
|
|
4395
|
+
setRowKeys(rowSelectionMode === "single" ? next.slice(0, 1) : next);
|
|
4396
|
+
},
|
|
4397
|
+
getSelectedColumnKeys: () => [...columnKeys],
|
|
4398
|
+
setSelectedColumnKeys: (keys) => {
|
|
4399
|
+
if (!columnSelection) return;
|
|
4400
|
+
const next = [...new Set(keys)].filter((key) => columns.some((column) => column.key === key && !column.rowNumber && !column.rowSelection && !column.rowDragHandle));
|
|
4401
|
+
setColumnKeys(typeof columnSelection === "object" && columnSelection.mode === "single" ? next.slice(0, 1) : next);
|
|
4402
|
+
},
|
|
4403
|
+
clearSelection: () => {
|
|
4404
|
+
setSelectionRange(null);
|
|
4405
|
+
setSelection(null);
|
|
4406
|
+
setRowKeys([]);
|
|
4407
|
+
setColumnKeys([]);
|
|
4408
|
+
rowAnchorRef.current = null;
|
|
4409
|
+
setEditing(null);
|
|
4410
|
+
},
|
|
4411
|
+
startEdit: (target) => {
|
|
4412
|
+
const cell = target ? resolveDataCell(target) : selection ? resolveDataCell(selection) : null;
|
|
4413
|
+
if (!cell || !isCellEditable(cell)) return false;
|
|
4414
|
+
setSelectionRange(null);
|
|
4415
|
+
setSelection(cell);
|
|
4416
|
+
beginEdit(cell);
|
|
4417
|
+
return true;
|
|
4418
|
+
},
|
|
4419
|
+
commitEdit: () => commitEdit(),
|
|
4420
|
+
cancelEdit: () => setEditing(null)
|
|
4421
|
+
};
|
|
4422
|
+
});
|
|
4339
4423
|
const rootStyle = {
|
|
4340
4424
|
width,
|
|
4341
4425
|
height: autoHeight ? effectiveHeight : height,
|
|
@@ -4534,6 +4618,10 @@ function Table({
|
|
|
4534
4618
|
}
|
|
4535
4619
|
if (event.detail > 1) return;
|
|
4536
4620
|
clickedCellRef.current = cell;
|
|
4621
|
+
const column = columns[cell.columnIndex];
|
|
4622
|
+
const row = rows[cell.rowIndex];
|
|
4623
|
+
onCellClick?.({ ...cell, row, column, value: column.dataIndex === void 0 ? void 0 : row[column.dataIndex] }, event);
|
|
4624
|
+
if (event.defaultPrevented) return;
|
|
4537
4625
|
setSelectionRange(null);
|
|
4538
4626
|
scrollerRef.current?.focus({ preventScroll: true });
|
|
4539
4627
|
setSelection(cell);
|
|
@@ -4544,7 +4632,12 @@ function Table({
|
|
|
4544
4632
|
},
|
|
4545
4633
|
onDoubleClick: (event) => {
|
|
4546
4634
|
const cell = clickedCellRef.current ?? locateCell(event.clientX, event.clientY);
|
|
4547
|
-
if (cell)
|
|
4635
|
+
if (!cell) return;
|
|
4636
|
+
const column = columns[cell.columnIndex];
|
|
4637
|
+
if (column.rowNumber || column.rowSelection || column.rowDragHandle) return;
|
|
4638
|
+
const row = rows[cell.rowIndex];
|
|
4639
|
+
onCellDoubleClick?.({ ...cell, row, column, value: column.dataIndex === void 0 ? void 0 : row[column.dataIndex] }, event);
|
|
4640
|
+
if (!event.defaultPrevented) beginEdit(cell);
|
|
4548
4641
|
},
|
|
4549
4642
|
onContextMenu: handleContextMenu
|
|
4550
4643
|
}
|
|
@@ -4557,7 +4650,7 @@ function Table({
|
|
|
4557
4650
|
className: "rvg-text-scroll-content",
|
|
4558
4651
|
style: { left: -fixedWidth, width: contentWidth, transform: `translateX(${-currentScroll.left}px)` },
|
|
4559
4652
|
children: [
|
|
4560
|
-
columns.map((column, columnIndex) => column.fixed || columnIndex
|
|
4653
|
+
columns.map((column, columnIndex) => column.fixed || columnIndex >= utilityColumnCount && headerDepth > 1 ? null : columnIndex >= domRange.columnStart && columnIndex < domRange.columnEnd ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: renderHeaderTitle(columnIndex, getScrollableColumnLeft(columnIndex)) }, column.key) : null),
|
|
4561
4654
|
headerCells.map((cell) => {
|
|
4562
4655
|
if (columns[cell.startIndex]?.fixed) return null;
|
|
4563
4656
|
if (cell.endIndex < domRange.columnStart || cell.startIndex >= domRange.columnEnd) return null;
|
|
@@ -4575,7 +4668,7 @@ function Table({
|
|
|
4575
4668
|
const left = column.fixed === "left" ? leftFixedOffsets.get(columnIndex) ?? 0 : viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metrics[columnIndex].width;
|
|
4576
4669
|
return renderCellText(rowIndex, columnIndex, left);
|
|
4577
4670
|
})) }),
|
|
4578
|
-
columns.map((column, columnIndex) => columnIndex < utilityColumnCount || headerDepth === 1
|
|
4671
|
+
columns.map((column, columnIndex) => column.fixed && (columnIndex < utilityColumnCount || headerDepth === 1) ? renderHeaderTitle(columnIndex, column.fixed === "right" ? viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metrics[columnIndex].width : column.fixed === "left" ? leftFixedOffsets.get(columnIndex) ?? 0 : getScrollableColumnLeft(columnIndex)) : null),
|
|
4579
4672
|
headerCells.map((cell) => columns[cell.startIndex]?.fixed ? renderGroupedHeaderCell(cell) : null),
|
|
4580
4673
|
fixedWidth > 0 && currentScroll.left > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rvg-text-fixed-shadow is-left", style: { left: fixedWidth } }),
|
|
4581
4674
|
rightFixedWidth > 0 && currentScroll.left < contentWidth - viewport.width && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rvg-text-fixed-shadow is-right", style: { right: rightFixedWidth } }),
|
|
@@ -4792,7 +4885,7 @@ function Table({
|
|
|
4792
4885
|
const affectedRows = selectedIndices.includes(cell.rowIndex) ? selectedIndices : [cell.rowIndex];
|
|
4793
4886
|
const cellContext = { ...cell, row, column, value: dataIndex === void 0 ? void 0 : row[dataIndex] };
|
|
4794
4887
|
return renderConfiguredContextMenu(resolveContextMenuSection(customContextMenuConfig?.cell, DEFAULT_CELL_CONTEXT_MENU), cellContext, (item, override) => {
|
|
4795
|
-
if (item === "edit") return renderContextMenuButton("cell-edit", cellContext, labels.edit, () => beginEdit(cell), override, { disabled: !
|
|
4888
|
+
if (item === "edit") return renderContextMenuButton("cell-edit", cellContext, labels.edit, () => beginEdit(cell), override, { disabled: !isCellEditable(cell), icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ContextMenuIcon, { type: "edit" }) });
|
|
4796
4889
|
if (item === "copy") return renderContextMenuButton("cell-copy", cellContext, labels.copyContent, async () => {
|
|
4797
4890
|
try {
|
|
4798
4891
|
await navigator.clipboard.writeText(getCellLabel(cell.rowIndex, cell.columnIndex));
|
|
@@ -5032,6 +5125,7 @@ function Table({
|
|
|
5032
5125
|
loading && !hasCustomLoading && hasCompletedLoadRef.current && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rvg-refresh-loading", "aria-label": labels.refreshing, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LoadingSpinnerIcon, {}) })
|
|
5033
5126
|
] });
|
|
5034
5127
|
}
|
|
5128
|
+
var Table = (0, import_react5.forwardRef)(TableInner);
|
|
5035
5129
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5036
5130
|
0 && (module.exports = {
|
|
5037
5131
|
Table,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { ReactNode, CSSProperties } from 'react';
|
|
1
|
+
import { ReactNode, MouseEvent, CSSProperties, RefAttributes, ReactElement } from 'react';
|
|
3
2
|
|
|
4
3
|
type GridKey = string | number;
|
|
5
4
|
type SelectionMode = 'single' | 'multiple';
|
|
@@ -155,6 +154,14 @@ interface AxisSelectionConfig {
|
|
|
155
154
|
/** single uses radio-style selection, multiple uses checkbox-style selection. */
|
|
156
155
|
mode?: SelectionMode;
|
|
157
156
|
}
|
|
157
|
+
interface RowSelectionConfig extends AxisSelectionConfig {
|
|
158
|
+
/** Show the selection column. Defaults to true; when false, click body cells to select rows. */
|
|
159
|
+
showCheckbox?: boolean;
|
|
160
|
+
}
|
|
161
|
+
interface TableRowNumberConfig {
|
|
162
|
+
/** Fix the row number column to the left. Defaults to true. */
|
|
163
|
+
fixed?: boolean;
|
|
164
|
+
}
|
|
158
165
|
/**
|
|
159
166
|
* Column definition consumed by both the canvas renderer and DOM editor layer.
|
|
160
167
|
*
|
|
@@ -179,7 +186,7 @@ interface GridColumn<Row> {
|
|
|
179
186
|
/** Text alignment for body cells and drag previews. */
|
|
180
187
|
align?: 'left' | 'center' | 'right';
|
|
181
188
|
/** Enables double-click / Enter editing when an editor or fallback input exists. */
|
|
182
|
-
editable?: boolean;
|
|
189
|
+
editable?: boolean | ((value: unknown, row: Row, rowIndex: number) => boolean);
|
|
183
190
|
/** Built-in editor configuration for text, selectable, date, time, and range cells. */
|
|
184
191
|
editor?: {
|
|
185
192
|
type: 'text';
|
|
@@ -241,6 +248,31 @@ interface CellChange<Row> extends GridSelection {
|
|
|
241
248
|
previousValue: unknown;
|
|
242
249
|
row: Row;
|
|
243
250
|
}
|
|
251
|
+
/** Data cell identity and content passed to mouse callbacks. */
|
|
252
|
+
interface TableCellContext<Row> extends GridSelection {
|
|
253
|
+
row: Row;
|
|
254
|
+
column: GridColumn<Row>;
|
|
255
|
+
value: unknown;
|
|
256
|
+
}
|
|
257
|
+
/** Imperative Table API. Selection getters reflect the latest committed render. */
|
|
258
|
+
interface TableRef<Row extends object> {
|
|
259
|
+
focus: () => void;
|
|
260
|
+
/** Reveal a data cell without changing selection; false if the target is unavailable. */
|
|
261
|
+
scrollToCell: (target: GridSelectionTarget) => boolean;
|
|
262
|
+
getSelectedCell: () => TableCellContext<Row> | null;
|
|
263
|
+
setSelectedCell: (target: GridSelectionTarget | null) => boolean;
|
|
264
|
+
getSelectedRowKeys: () => GridKey[];
|
|
265
|
+
getSelectedRows: () => Row[];
|
|
266
|
+
setSelectedRowKeys: (keys: GridKey[]) => void;
|
|
267
|
+
getSelectedColumnKeys: () => string[];
|
|
268
|
+
setSelectedColumnKeys: (keys: string[]) => void;
|
|
269
|
+
/** Clear cell, range, row, and column selections. */
|
|
270
|
+
clearSelection: () => void;
|
|
271
|
+
/** Select and edit a cell, or edit the current selection. Returns false for invalid or read-only cells. */
|
|
272
|
+
startEdit: (target?: GridSelectionTarget) => boolean;
|
|
273
|
+
commitEdit: () => void;
|
|
274
|
+
cancelEdit: () => void;
|
|
275
|
+
}
|
|
244
276
|
/** Fired when the consumer wants to observe or extend a cell context menu. */
|
|
245
277
|
interface ContextMenuEvent<Row> extends GridSelection {
|
|
246
278
|
row: Row;
|
|
@@ -331,13 +363,13 @@ interface TableProps<Row extends object> {
|
|
|
331
363
|
/** Show and position the summary row for columns with summary configured. */
|
|
332
364
|
summary?: TableSummaryConfig;
|
|
333
365
|
/** Show an automatically generated row number column on the left. */
|
|
334
|
-
rowNumber?: boolean;
|
|
366
|
+
rowNumber?: boolean | TableRowNumberConfig;
|
|
335
367
|
selectedCell?: GridSelectionTarget | null;
|
|
336
368
|
defaultSelectedCell?: GridSelectionTarget | null;
|
|
337
369
|
onSelectedCellChange?: (selection: SelectedCellChange | null) => void;
|
|
338
370
|
/** Enable spreadsheet-style mouse drag selection across multiple body cells. Defaults to false. */
|
|
339
371
|
rangeSelection?: boolean;
|
|
340
|
-
rowSelection?: boolean |
|
|
372
|
+
rowSelection?: boolean | RowSelectionConfig;
|
|
341
373
|
selectedRowKeys?: GridKey[];
|
|
342
374
|
defaultSelectedRowKeys?: GridKey[];
|
|
343
375
|
onSelectedRowChange?: (keys: GridKey[], rows: Row[], indices: number[]) => void;
|
|
@@ -371,6 +403,10 @@ interface TableProps<Row extends object> {
|
|
|
371
403
|
/** Overrides the built-in text filtering. Return the rows that match the internally managed filter values. */
|
|
372
404
|
onFilterChange?: (rows: Row[], values: Readonly<Record<string, string>>) => Row[];
|
|
373
405
|
onCellChange?: (change: CellChange<Row>) => void | Promise<void>;
|
|
406
|
+
/** Fires on a data cell click, before the default selection behavior. */
|
|
407
|
+
onCellClick?: (cell: TableCellContext<Row>, event: MouseEvent<HTMLElement>) => void;
|
|
408
|
+
/** Fires before double-click editing. preventDefault() cancels editing. */
|
|
409
|
+
onCellDoubleClick?: (cell: TableCellContext<Row>, event: MouseEvent<HTMLElement>) => void;
|
|
374
410
|
onCellContextMenu?: (event: ContextMenuEvent<Row>) => void;
|
|
375
411
|
/** true uses the built-in menu, false disables custom menus, object customizes menu content and order. */
|
|
376
412
|
contextMenu?: TableContextMenu<Row>;
|
|
@@ -386,7 +422,7 @@ interface ViewportRange {
|
|
|
386
422
|
columnEnd: number;
|
|
387
423
|
}
|
|
388
424
|
|
|
389
|
-
declare
|
|
425
|
+
declare const Table: <Row extends object>(props: TableProps<Row> & RefAttributes<TableRef<Row>>) => ReactElement;
|
|
390
426
|
|
|
391
427
|
type LayoutColumn<Row> = GridColumn<Row> & {
|
|
392
428
|
rowSelection?: boolean;
|
|
@@ -433,4 +469,4 @@ declare function hitTestColumn(metrics: ColumnMetric[], contentX: number): numbe
|
|
|
433
469
|
|
|
434
470
|
type TableFilterValues = Record<string, string>;
|
|
435
471
|
|
|
436
|
-
export { type AxisSelectionConfig, type CellChange, type ContextMenuEvent, type GridCellPosition, type GridColumn, type GridKey, type GridSelection, type GridSelectionTarget, type GridSortState, type SelectedCellChange, type SelectionMode, type SortDirection, Table, type CellChange as TableCellChange, type GridCellPosition as TableCellPosition, type TableCellSpan, type TableCellSpanRule, type TableCellSpanRuleContext, type TableCellSpans, type GridColumn as TableColumn, type TableContextMenu, type TableContextMenuConfig, type ContextMenuEvent as TableContextMenuEvent, type GridSelection as TableEditingCell, type TableFilterValues, type TableHighlightConfig, type GridKey as TableKey, type TableLabels, type TableLayoutConfig, type TableLocaleCode, type TableLocaleConfig, type TableProps, type TableResolvedCellSpan, type GridSortState as TableSorter, type TableSummaryConfig, type TableTooltipConfig, type ViewportRange as TableViewportRange, type TableVirtualizedConfig, Table as VelocityGrid, type TableCellSpan as VelocityGridCellSpan, type TableCellSpanRule as VelocityGridCellSpanRule, type TableCellSpanRuleContext as VelocityGridCellSpanRuleContext, type TableCellSpans as VelocityGridCellSpans, type TableContextMenu as VelocityGridContextMenu, type TableContextMenuConfig as VelocityGridContextMenuConfig, type TableHighlightConfig as VelocityGridHighlightConfig, type TableLabels as VelocityGridLabels, type TableLayoutConfig as VelocityGridLayoutConfig, type TableLocaleCode as VelocityGridLocaleCode, type TableLocaleConfig as VelocityGridLocaleConfig, type TableProps as VelocityGridProps, type TableResolvedCellSpan as VelocityGridResolvedCellSpan, type TableSummaryConfig as VelocityGridSummaryConfig, type TableTooltipConfig as VelocityGridTooltipConfig, type TableVirtualizedConfig as VelocityGridVirtualizedConfig, type ViewportRange, buildColumnMetrics, getViewportRange, hitTestColumn };
|
|
472
|
+
export { type AxisSelectionConfig, type CellChange, type ContextMenuEvent, type GridCellPosition, type GridColumn, type GridKey, type GridSelection, type GridSelectionTarget, type GridSortState, type RowSelectionConfig, type SelectedCellChange, type SelectionMode, type SortDirection, Table, type CellChange as TableCellChange, type TableCellContext, type GridCellPosition as TableCellPosition, type TableCellSpan, type TableCellSpanRule, type TableCellSpanRuleContext, type TableCellSpans, type GridColumn as TableColumn, type TableContextMenu, type TableContextMenuConfig, type ContextMenuEvent as TableContextMenuEvent, type GridSelection as TableEditingCell, type TableFilterValues, type TableHighlightConfig, type GridKey as TableKey, type TableLabels, type TableLayoutConfig, type TableLocaleCode, type TableLocaleConfig, type TableProps, type TableRef, type TableResolvedCellSpan, type TableRowNumberConfig, type GridSortState as TableSorter, type TableSummaryConfig, type TableTooltipConfig, type ViewportRange as TableViewportRange, type TableVirtualizedConfig, Table as VelocityGrid, type TableCellSpan as VelocityGridCellSpan, type TableCellSpanRule as VelocityGridCellSpanRule, type TableCellSpanRuleContext as VelocityGridCellSpanRuleContext, type TableCellSpans as VelocityGridCellSpans, type TableContextMenu as VelocityGridContextMenu, type TableContextMenuConfig as VelocityGridContextMenuConfig, type TableHighlightConfig as VelocityGridHighlightConfig, type TableLabels as VelocityGridLabels, type TableLayoutConfig as VelocityGridLayoutConfig, type TableLocaleCode as VelocityGridLocaleCode, type TableLocaleConfig as VelocityGridLocaleConfig, type TableProps as VelocityGridProps, type TableRef as VelocityGridRef, type TableResolvedCellSpan as VelocityGridResolvedCellSpan, type TableSummaryConfig as VelocityGridSummaryConfig, type TableTooltipConfig as VelocityGridTooltipConfig, type TableVirtualizedConfig as VelocityGridVirtualizedConfig, type ViewportRange, buildColumnMetrics, getViewportRange, hitTestColumn };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { ReactNode, CSSProperties } from 'react';
|
|
1
|
+
import { ReactNode, MouseEvent, CSSProperties, RefAttributes, ReactElement } from 'react';
|
|
3
2
|
|
|
4
3
|
type GridKey = string | number;
|
|
5
4
|
type SelectionMode = 'single' | 'multiple';
|
|
@@ -155,6 +154,14 @@ interface AxisSelectionConfig {
|
|
|
155
154
|
/** single uses radio-style selection, multiple uses checkbox-style selection. */
|
|
156
155
|
mode?: SelectionMode;
|
|
157
156
|
}
|
|
157
|
+
interface RowSelectionConfig extends AxisSelectionConfig {
|
|
158
|
+
/** Show the selection column. Defaults to true; when false, click body cells to select rows. */
|
|
159
|
+
showCheckbox?: boolean;
|
|
160
|
+
}
|
|
161
|
+
interface TableRowNumberConfig {
|
|
162
|
+
/** Fix the row number column to the left. Defaults to true. */
|
|
163
|
+
fixed?: boolean;
|
|
164
|
+
}
|
|
158
165
|
/**
|
|
159
166
|
* Column definition consumed by both the canvas renderer and DOM editor layer.
|
|
160
167
|
*
|
|
@@ -179,7 +186,7 @@ interface GridColumn<Row> {
|
|
|
179
186
|
/** Text alignment for body cells and drag previews. */
|
|
180
187
|
align?: 'left' | 'center' | 'right';
|
|
181
188
|
/** Enables double-click / Enter editing when an editor or fallback input exists. */
|
|
182
|
-
editable?: boolean;
|
|
189
|
+
editable?: boolean | ((value: unknown, row: Row, rowIndex: number) => boolean);
|
|
183
190
|
/** Built-in editor configuration for text, selectable, date, time, and range cells. */
|
|
184
191
|
editor?: {
|
|
185
192
|
type: 'text';
|
|
@@ -241,6 +248,31 @@ interface CellChange<Row> extends GridSelection {
|
|
|
241
248
|
previousValue: unknown;
|
|
242
249
|
row: Row;
|
|
243
250
|
}
|
|
251
|
+
/** Data cell identity and content passed to mouse callbacks. */
|
|
252
|
+
interface TableCellContext<Row> extends GridSelection {
|
|
253
|
+
row: Row;
|
|
254
|
+
column: GridColumn<Row>;
|
|
255
|
+
value: unknown;
|
|
256
|
+
}
|
|
257
|
+
/** Imperative Table API. Selection getters reflect the latest committed render. */
|
|
258
|
+
interface TableRef<Row extends object> {
|
|
259
|
+
focus: () => void;
|
|
260
|
+
/** Reveal a data cell without changing selection; false if the target is unavailable. */
|
|
261
|
+
scrollToCell: (target: GridSelectionTarget) => boolean;
|
|
262
|
+
getSelectedCell: () => TableCellContext<Row> | null;
|
|
263
|
+
setSelectedCell: (target: GridSelectionTarget | null) => boolean;
|
|
264
|
+
getSelectedRowKeys: () => GridKey[];
|
|
265
|
+
getSelectedRows: () => Row[];
|
|
266
|
+
setSelectedRowKeys: (keys: GridKey[]) => void;
|
|
267
|
+
getSelectedColumnKeys: () => string[];
|
|
268
|
+
setSelectedColumnKeys: (keys: string[]) => void;
|
|
269
|
+
/** Clear cell, range, row, and column selections. */
|
|
270
|
+
clearSelection: () => void;
|
|
271
|
+
/** Select and edit a cell, or edit the current selection. Returns false for invalid or read-only cells. */
|
|
272
|
+
startEdit: (target?: GridSelectionTarget) => boolean;
|
|
273
|
+
commitEdit: () => void;
|
|
274
|
+
cancelEdit: () => void;
|
|
275
|
+
}
|
|
244
276
|
/** Fired when the consumer wants to observe or extend a cell context menu. */
|
|
245
277
|
interface ContextMenuEvent<Row> extends GridSelection {
|
|
246
278
|
row: Row;
|
|
@@ -331,13 +363,13 @@ interface TableProps<Row extends object> {
|
|
|
331
363
|
/** Show and position the summary row for columns with summary configured. */
|
|
332
364
|
summary?: TableSummaryConfig;
|
|
333
365
|
/** Show an automatically generated row number column on the left. */
|
|
334
|
-
rowNumber?: boolean;
|
|
366
|
+
rowNumber?: boolean | TableRowNumberConfig;
|
|
335
367
|
selectedCell?: GridSelectionTarget | null;
|
|
336
368
|
defaultSelectedCell?: GridSelectionTarget | null;
|
|
337
369
|
onSelectedCellChange?: (selection: SelectedCellChange | null) => void;
|
|
338
370
|
/** Enable spreadsheet-style mouse drag selection across multiple body cells. Defaults to false. */
|
|
339
371
|
rangeSelection?: boolean;
|
|
340
|
-
rowSelection?: boolean |
|
|
372
|
+
rowSelection?: boolean | RowSelectionConfig;
|
|
341
373
|
selectedRowKeys?: GridKey[];
|
|
342
374
|
defaultSelectedRowKeys?: GridKey[];
|
|
343
375
|
onSelectedRowChange?: (keys: GridKey[], rows: Row[], indices: number[]) => void;
|
|
@@ -371,6 +403,10 @@ interface TableProps<Row extends object> {
|
|
|
371
403
|
/** Overrides the built-in text filtering. Return the rows that match the internally managed filter values. */
|
|
372
404
|
onFilterChange?: (rows: Row[], values: Readonly<Record<string, string>>) => Row[];
|
|
373
405
|
onCellChange?: (change: CellChange<Row>) => void | Promise<void>;
|
|
406
|
+
/** Fires on a data cell click, before the default selection behavior. */
|
|
407
|
+
onCellClick?: (cell: TableCellContext<Row>, event: MouseEvent<HTMLElement>) => void;
|
|
408
|
+
/** Fires before double-click editing. preventDefault() cancels editing. */
|
|
409
|
+
onCellDoubleClick?: (cell: TableCellContext<Row>, event: MouseEvent<HTMLElement>) => void;
|
|
374
410
|
onCellContextMenu?: (event: ContextMenuEvent<Row>) => void;
|
|
375
411
|
/** true uses the built-in menu, false disables custom menus, object customizes menu content and order. */
|
|
376
412
|
contextMenu?: TableContextMenu<Row>;
|
|
@@ -386,7 +422,7 @@ interface ViewportRange {
|
|
|
386
422
|
columnEnd: number;
|
|
387
423
|
}
|
|
388
424
|
|
|
389
|
-
declare
|
|
425
|
+
declare const Table: <Row extends object>(props: TableProps<Row> & RefAttributes<TableRef<Row>>) => ReactElement;
|
|
390
426
|
|
|
391
427
|
type LayoutColumn<Row> = GridColumn<Row> & {
|
|
392
428
|
rowSelection?: boolean;
|
|
@@ -433,4 +469,4 @@ declare function hitTestColumn(metrics: ColumnMetric[], contentX: number): numbe
|
|
|
433
469
|
|
|
434
470
|
type TableFilterValues = Record<string, string>;
|
|
435
471
|
|
|
436
|
-
export { type AxisSelectionConfig, type CellChange, type ContextMenuEvent, type GridCellPosition, type GridColumn, type GridKey, type GridSelection, type GridSelectionTarget, type GridSortState, type SelectedCellChange, type SelectionMode, type SortDirection, Table, type CellChange as TableCellChange, type GridCellPosition as TableCellPosition, type TableCellSpan, type TableCellSpanRule, type TableCellSpanRuleContext, type TableCellSpans, type GridColumn as TableColumn, type TableContextMenu, type TableContextMenuConfig, type ContextMenuEvent as TableContextMenuEvent, type GridSelection as TableEditingCell, type TableFilterValues, type TableHighlightConfig, type GridKey as TableKey, type TableLabels, type TableLayoutConfig, type TableLocaleCode, type TableLocaleConfig, type TableProps, type TableResolvedCellSpan, type GridSortState as TableSorter, type TableSummaryConfig, type TableTooltipConfig, type ViewportRange as TableViewportRange, type TableVirtualizedConfig, Table as VelocityGrid, type TableCellSpan as VelocityGridCellSpan, type TableCellSpanRule as VelocityGridCellSpanRule, type TableCellSpanRuleContext as VelocityGridCellSpanRuleContext, type TableCellSpans as VelocityGridCellSpans, type TableContextMenu as VelocityGridContextMenu, type TableContextMenuConfig as VelocityGridContextMenuConfig, type TableHighlightConfig as VelocityGridHighlightConfig, type TableLabels as VelocityGridLabels, type TableLayoutConfig as VelocityGridLayoutConfig, type TableLocaleCode as VelocityGridLocaleCode, type TableLocaleConfig as VelocityGridLocaleConfig, type TableProps as VelocityGridProps, type TableResolvedCellSpan as VelocityGridResolvedCellSpan, type TableSummaryConfig as VelocityGridSummaryConfig, type TableTooltipConfig as VelocityGridTooltipConfig, type TableVirtualizedConfig as VelocityGridVirtualizedConfig, type ViewportRange, buildColumnMetrics, getViewportRange, hitTestColumn };
|
|
472
|
+
export { type AxisSelectionConfig, type CellChange, type ContextMenuEvent, type GridCellPosition, type GridColumn, type GridKey, type GridSelection, type GridSelectionTarget, type GridSortState, type RowSelectionConfig, type SelectedCellChange, type SelectionMode, type SortDirection, Table, type CellChange as TableCellChange, type TableCellContext, type GridCellPosition as TableCellPosition, type TableCellSpan, type TableCellSpanRule, type TableCellSpanRuleContext, type TableCellSpans, type GridColumn as TableColumn, type TableContextMenu, type TableContextMenuConfig, type ContextMenuEvent as TableContextMenuEvent, type GridSelection as TableEditingCell, type TableFilterValues, type TableHighlightConfig, type GridKey as TableKey, type TableLabels, type TableLayoutConfig, type TableLocaleCode, type TableLocaleConfig, type TableProps, type TableRef, type TableResolvedCellSpan, type TableRowNumberConfig, type GridSortState as TableSorter, type TableSummaryConfig, type TableTooltipConfig, type ViewportRange as TableViewportRange, type TableVirtualizedConfig, Table as VelocityGrid, type TableCellSpan as VelocityGridCellSpan, type TableCellSpanRule as VelocityGridCellSpanRule, type TableCellSpanRuleContext as VelocityGridCellSpanRuleContext, type TableCellSpans as VelocityGridCellSpans, type TableContextMenu as VelocityGridContextMenu, type TableContextMenuConfig as VelocityGridContextMenuConfig, type TableHighlightConfig as VelocityGridHighlightConfig, type TableLabels as VelocityGridLabels, type TableLayoutConfig as VelocityGridLayoutConfig, type TableLocaleCode as VelocityGridLocaleCode, type TableLocaleConfig as VelocityGridLocaleConfig, type TableProps as VelocityGridProps, type TableRef as VelocityGridRef, type TableResolvedCellSpan as VelocityGridResolvedCellSpan, type TableSummaryConfig as VelocityGridSummaryConfig, type TableTooltipConfig as VelocityGridTooltipConfig, type TableVirtualizedConfig as VelocityGridVirtualizedConfig, type ViewportRange, buildColumnMetrics, getViewportRange, hitTestColumn };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/Table.tsx
|
|
2
|
-
import { Fragment as Fragment2, useCallback as useCallback2, useEffect as useEffect2, useLayoutEffect as useLayoutEffect2, useMemo, useRef as useRef2, useState as useState4 } from "react";
|
|
2
|
+
import { forwardRef, useImperativeHandle, Fragment as Fragment2, useCallback as useCallback2, useEffect as useEffect2, useLayoutEffect as useLayoutEffect2, useMemo, useRef as useRef2, useState as useState4 } from "react";
|
|
3
3
|
import { flushSync } from "react-dom";
|
|
4
4
|
|
|
5
5
|
// src/components/EmptyState.tsx
|
|
@@ -1492,7 +1492,7 @@ function resolveContextMenuSection(section, defaults) {
|
|
|
1492
1492
|
}
|
|
1493
1493
|
return defaults;
|
|
1494
1494
|
}
|
|
1495
|
-
function
|
|
1495
|
+
function TableInner({
|
|
1496
1496
|
columns: columnProps,
|
|
1497
1497
|
rows: sourceRows,
|
|
1498
1498
|
rowKey,
|
|
@@ -1538,13 +1538,15 @@ function Table({
|
|
|
1538
1538
|
onSortChange,
|
|
1539
1539
|
onFilterChange,
|
|
1540
1540
|
onCellChange,
|
|
1541
|
+
onCellClick,
|
|
1542
|
+
onCellDoubleClick,
|
|
1541
1543
|
onCellContextMenu,
|
|
1542
1544
|
contextMenu: contextMenuConfig = true,
|
|
1543
1545
|
emptyContent,
|
|
1544
1546
|
className = "",
|
|
1545
1547
|
style,
|
|
1546
1548
|
ariaLabel = "Data grid"
|
|
1547
|
-
}) {
|
|
1549
|
+
}, ref) {
|
|
1548
1550
|
const [sourceColumns, setSourceColumns] = useState4(columnProps);
|
|
1549
1551
|
useEffect2(() => {
|
|
1550
1552
|
setSourceColumns((current) => reconcileColumns(current, columnProps));
|
|
@@ -1590,6 +1592,7 @@ function Table({
|
|
|
1590
1592
|
const customContextMenuConfig = typeof contextMenuConfig === "object" ? contextMenuConfig : void 0;
|
|
1591
1593
|
const [resizedColumnWidths, setResizedColumnWidths] = useState4({});
|
|
1592
1594
|
const leafSourceColumns = useMemo(() => flattenDataColumns(sourceColumns), [sourceColumns]);
|
|
1595
|
+
const showRowCheckbox = Boolean(rowSelection) && (typeof rowSelection !== "object" || rowSelection.showCheckbox !== false);
|
|
1593
1596
|
useEffect2(() => {
|
|
1594
1597
|
if (!isProductionRuntime() && hasNestedFixedColumns(sourceColumns)) {
|
|
1595
1598
|
console.warn("[Table] Multi-level headers only support fixed columns on top-level columns. Nested fixed values are ignored.");
|
|
@@ -1600,19 +1603,19 @@ function Table({
|
|
|
1600
1603
|
if (rowDraggable) {
|
|
1601
1604
|
utilityColumns.push({ key: "__rvg_row_drag__", title: "", width: 36, align: "center", fixed: "left", rowDragHandle: true });
|
|
1602
1605
|
}
|
|
1603
|
-
if (
|
|
1606
|
+
if (showRowCheckbox) {
|
|
1604
1607
|
utilityColumns.push({ key: "__rvg_row_selection__", title: "", width: 44, align: "center", fixed: "left", rowSelection: true });
|
|
1605
1608
|
}
|
|
1606
1609
|
if (rowNumber) {
|
|
1607
|
-
utilityColumns.push({ key: "__rvg_row_number__", title: "#", width: getRowNumberColumnWidth(sourceRows.length), align: "center", fixed: "left", rowNumber: true });
|
|
1610
|
+
utilityColumns.push({ key: "__rvg_row_number__", title: "#", width: getRowNumberColumnWidth(sourceRows.length), align: "center", fixed: typeof rowNumber === "object" && rowNumber.fixed === false ? void 0 : "left", rowNumber: true });
|
|
1608
1611
|
}
|
|
1609
1612
|
const dataColumns = leafSourceColumns.map((column) => {
|
|
1610
1613
|
const resizedWidth = resizedColumnWidths[column.key];
|
|
1611
1614
|
return resizedWidth === void 0 ? column : { ...column, width: resizedWidth };
|
|
1612
1615
|
});
|
|
1613
1616
|
return [...utilityColumns, ...dataColumns];
|
|
1614
|
-
}, [leafSourceColumns, resizedColumnWidths, rowDraggable, rowNumber,
|
|
1615
|
-
const utilityColumnCount = (rowDraggable ? 1 : 0) + (
|
|
1617
|
+
}, [leafSourceColumns, resizedColumnWidths, rowDraggable, rowNumber, showRowCheckbox, sourceRows.length]);
|
|
1618
|
+
const utilityColumnCount = (rowDraggable ? 1 : 0) + (showRowCheckbox ? 1 : 0) + (rowNumber ? 1 : 0);
|
|
1616
1619
|
const headerCells = useMemo(() => buildHeaderCells(sourceColumns, utilityColumnCount, headerDepth), [headerDepth, sourceColumns, utilityColumnCount]);
|
|
1617
1620
|
const activeCustomHeaderLevels = useMemo(() => {
|
|
1618
1621
|
const levels = /* @__PURE__ */ new Map();
|
|
@@ -3318,9 +3321,15 @@ function Table({
|
|
|
3318
3321
|
scrollRef.current = { left: scroller.scrollLeft, top: scroller.scrollTop };
|
|
3319
3322
|
scheduleDraw();
|
|
3320
3323
|
}, [bodyTop, columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, scheduleDraw, viewport.width]);
|
|
3324
|
+
const isCellEditable = useCallback2((cell) => {
|
|
3325
|
+
const column = columns[cell.columnIndex];
|
|
3326
|
+
const row = rows[cell.rowIndex];
|
|
3327
|
+
if (!column || !row || column.dataIndex === void 0 || column.rowNumber || column.rowSelection || column.rowDragHandle) return false;
|
|
3328
|
+
return typeof column.editable === "function" ? column.editable(row[column.dataIndex], row, cell.rowIndex) : column.editable === true;
|
|
3329
|
+
}, [columns, rows]);
|
|
3321
3330
|
const beginEdit = useCallback2((cell) => {
|
|
3322
3331
|
const column = columns[cell.columnIndex];
|
|
3323
|
-
if (!
|
|
3332
|
+
if (!isCellEditable(cell) || column.dataIndex === void 0) return;
|
|
3324
3333
|
const value = rows[cell.rowIndex]?.[column.dataIndex];
|
|
3325
3334
|
setDraft(value == null ? "" : String(value));
|
|
3326
3335
|
const scroller = scrollerRef.current;
|
|
@@ -3362,7 +3371,7 @@ function Table({
|
|
|
3362
3371
|
return;
|
|
3363
3372
|
}
|
|
3364
3373
|
setEditing(cell);
|
|
3365
|
-
}, [columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, metrics, rightFixedWidth, rowHeight, rows, scheduleDraw, viewport.width]);
|
|
3374
|
+
}, [columns, fixedHeader, fixedWidth, getCellDisplayWidth, getCellSpan, getScrollableColumnLeft, isCellEditable, metrics, rightFixedWidth, rowHeight, rows, scheduleDraw, viewport.width]);
|
|
3366
3375
|
const getCellEditKey = (cell) => `${typeof cell.rowKey}:${String(cell.rowKey)}\0${cell.columnKey}`;
|
|
3367
3376
|
const markCellEdited = (cell, previousValue, nextValue) => {
|
|
3368
3377
|
const key = getCellEditKey(cell);
|
|
@@ -3390,6 +3399,10 @@ function Table({
|
|
|
3390
3399
|
};
|
|
3391
3400
|
const commitEdit = useCallback2((nextDraft, close = true) => {
|
|
3392
3401
|
if (!editing) return;
|
|
3402
|
+
if (!isCellEditable(editing)) {
|
|
3403
|
+
setEditing(null);
|
|
3404
|
+
return;
|
|
3405
|
+
}
|
|
3393
3406
|
const committedDraft = nextDraft ?? draft;
|
|
3394
3407
|
const column = columns[editing.columnIndex];
|
|
3395
3408
|
const row = rows[editing.rowIndex];
|
|
@@ -3404,7 +3417,7 @@ function Table({
|
|
|
3404
3417
|
onCellChange?.({ ...editing, row, value: committedValue, previousValue });
|
|
3405
3418
|
}
|
|
3406
3419
|
if (close) setEditing(null);
|
|
3407
|
-
}, [columns, draft, editing, onCellChange, rows]);
|
|
3420
|
+
}, [columns, draft, editing, isCellEditable, onCellChange, rows]);
|
|
3408
3421
|
const renderEditor = () => {
|
|
3409
3422
|
if (!editing || !editorStyle) return null;
|
|
3410
3423
|
const column = columns[editing.columnIndex];
|
|
@@ -4306,6 +4319,77 @@ function Table({
|
|
|
4306
4319
|
`summary:${column.key}`
|
|
4307
4320
|
);
|
|
4308
4321
|
};
|
|
4322
|
+
useImperativeHandle(ref, () => {
|
|
4323
|
+
const resolveDataCell = (target) => {
|
|
4324
|
+
const cell = resolveSelectionTarget(target);
|
|
4325
|
+
if (!cell) return null;
|
|
4326
|
+
const column = columns[cell.columnIndex];
|
|
4327
|
+
if (column.rowNumber || column.rowSelection || column.rowDragHandle) return null;
|
|
4328
|
+
const span = getCellSpan(cell.rowIndex, cell.columnIndex);
|
|
4329
|
+
if (!span) return cell;
|
|
4330
|
+
return {
|
|
4331
|
+
rowIndex: span.rowIndex,
|
|
4332
|
+
columnIndex: span.columnIndex,
|
|
4333
|
+
rowKey: getRowKey(rows[span.rowIndex], span.rowIndex),
|
|
4334
|
+
columnKey: columns[span.columnIndex].key
|
|
4335
|
+
};
|
|
4336
|
+
};
|
|
4337
|
+
return {
|
|
4338
|
+
focus: () => scrollerRef.current?.focus({ preventScroll: true }),
|
|
4339
|
+
scrollToCell: (target) => {
|
|
4340
|
+
const cell = resolveDataCell(target);
|
|
4341
|
+
if (!cell) return false;
|
|
4342
|
+
revealCell(cell);
|
|
4343
|
+
return true;
|
|
4344
|
+
},
|
|
4345
|
+
getSelectedCell: () => {
|
|
4346
|
+
if (!selection) return null;
|
|
4347
|
+
const cell = resolveDataCell(selection);
|
|
4348
|
+
if (!cell) return null;
|
|
4349
|
+
const column = columns[cell.columnIndex];
|
|
4350
|
+
const row = rows[cell.rowIndex];
|
|
4351
|
+
return { ...cell, row, column, value: column.dataIndex === void 0 ? void 0 : row[column.dataIndex] };
|
|
4352
|
+
},
|
|
4353
|
+
setSelectedCell: (target) => {
|
|
4354
|
+
const cell = target === null ? null : resolveDataCell(target);
|
|
4355
|
+
if (target !== null && !cell) return false;
|
|
4356
|
+
setSelectionRange(null);
|
|
4357
|
+
setSelection(cell);
|
|
4358
|
+
return true;
|
|
4359
|
+
},
|
|
4360
|
+
getSelectedRowKeys: () => [...rowKeys],
|
|
4361
|
+
getSelectedRows: () => rows.filter((row, index) => selectedRowKeySet.has(getRowKey(row, index))),
|
|
4362
|
+
setSelectedRowKeys: (keys) => {
|
|
4363
|
+
if (!rowSelection) return;
|
|
4364
|
+
const next = [...new Set(keys)];
|
|
4365
|
+
setRowKeys(rowSelectionMode === "single" ? next.slice(0, 1) : next);
|
|
4366
|
+
},
|
|
4367
|
+
getSelectedColumnKeys: () => [...columnKeys],
|
|
4368
|
+
setSelectedColumnKeys: (keys) => {
|
|
4369
|
+
if (!columnSelection) return;
|
|
4370
|
+
const next = [...new Set(keys)].filter((key) => columns.some((column) => column.key === key && !column.rowNumber && !column.rowSelection && !column.rowDragHandle));
|
|
4371
|
+
setColumnKeys(typeof columnSelection === "object" && columnSelection.mode === "single" ? next.slice(0, 1) : next);
|
|
4372
|
+
},
|
|
4373
|
+
clearSelection: () => {
|
|
4374
|
+
setSelectionRange(null);
|
|
4375
|
+
setSelection(null);
|
|
4376
|
+
setRowKeys([]);
|
|
4377
|
+
setColumnKeys([]);
|
|
4378
|
+
rowAnchorRef.current = null;
|
|
4379
|
+
setEditing(null);
|
|
4380
|
+
},
|
|
4381
|
+
startEdit: (target) => {
|
|
4382
|
+
const cell = target ? resolveDataCell(target) : selection ? resolveDataCell(selection) : null;
|
|
4383
|
+
if (!cell || !isCellEditable(cell)) return false;
|
|
4384
|
+
setSelectionRange(null);
|
|
4385
|
+
setSelection(cell);
|
|
4386
|
+
beginEdit(cell);
|
|
4387
|
+
return true;
|
|
4388
|
+
},
|
|
4389
|
+
commitEdit: () => commitEdit(),
|
|
4390
|
+
cancelEdit: () => setEditing(null)
|
|
4391
|
+
};
|
|
4392
|
+
});
|
|
4309
4393
|
const rootStyle = {
|
|
4310
4394
|
width,
|
|
4311
4395
|
height: autoHeight ? effectiveHeight : height,
|
|
@@ -4504,6 +4588,10 @@ function Table({
|
|
|
4504
4588
|
}
|
|
4505
4589
|
if (event.detail > 1) return;
|
|
4506
4590
|
clickedCellRef.current = cell;
|
|
4591
|
+
const column = columns[cell.columnIndex];
|
|
4592
|
+
const row = rows[cell.rowIndex];
|
|
4593
|
+
onCellClick?.({ ...cell, row, column, value: column.dataIndex === void 0 ? void 0 : row[column.dataIndex] }, event);
|
|
4594
|
+
if (event.defaultPrevented) return;
|
|
4507
4595
|
setSelectionRange(null);
|
|
4508
4596
|
scrollerRef.current?.focus({ preventScroll: true });
|
|
4509
4597
|
setSelection(cell);
|
|
@@ -4514,7 +4602,12 @@ function Table({
|
|
|
4514
4602
|
},
|
|
4515
4603
|
onDoubleClick: (event) => {
|
|
4516
4604
|
const cell = clickedCellRef.current ?? locateCell(event.clientX, event.clientY);
|
|
4517
|
-
if (cell)
|
|
4605
|
+
if (!cell) return;
|
|
4606
|
+
const column = columns[cell.columnIndex];
|
|
4607
|
+
if (column.rowNumber || column.rowSelection || column.rowDragHandle) return;
|
|
4608
|
+
const row = rows[cell.rowIndex];
|
|
4609
|
+
onCellDoubleClick?.({ ...cell, row, column, value: column.dataIndex === void 0 ? void 0 : row[column.dataIndex] }, event);
|
|
4610
|
+
if (!event.defaultPrevented) beginEdit(cell);
|
|
4518
4611
|
},
|
|
4519
4612
|
onContextMenu: handleContextMenu
|
|
4520
4613
|
}
|
|
@@ -4527,7 +4620,7 @@ function Table({
|
|
|
4527
4620
|
className: "rvg-text-scroll-content",
|
|
4528
4621
|
style: { left: -fixedWidth, width: contentWidth, transform: `translateX(${-currentScroll.left}px)` },
|
|
4529
4622
|
children: [
|
|
4530
|
-
columns.map((column, columnIndex) => column.fixed || columnIndex
|
|
4623
|
+
columns.map((column, columnIndex) => column.fixed || columnIndex >= utilityColumnCount && headerDepth > 1 ? null : columnIndex >= domRange.columnStart && columnIndex < domRange.columnEnd ? /* @__PURE__ */ jsx7("span", { children: renderHeaderTitle(columnIndex, getScrollableColumnLeft(columnIndex)) }, column.key) : null),
|
|
4531
4624
|
headerCells.map((cell) => {
|
|
4532
4625
|
if (columns[cell.startIndex]?.fixed) return null;
|
|
4533
4626
|
if (cell.endIndex < domRange.columnStart || cell.startIndex >= domRange.columnEnd) return null;
|
|
@@ -4545,7 +4638,7 @@ function Table({
|
|
|
4545
4638
|
const left = column.fixed === "left" ? leftFixedOffsets.get(columnIndex) ?? 0 : viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metrics[columnIndex].width;
|
|
4546
4639
|
return renderCellText(rowIndex, columnIndex, left);
|
|
4547
4640
|
})) }),
|
|
4548
|
-
columns.map((column, columnIndex) => columnIndex < utilityColumnCount || headerDepth === 1
|
|
4641
|
+
columns.map((column, columnIndex) => column.fixed && (columnIndex < utilityColumnCount || headerDepth === 1) ? renderHeaderTitle(columnIndex, column.fixed === "right" ? viewport.width - (rightFixedOffsets.get(columnIndex) ?? 0) - metrics[columnIndex].width : column.fixed === "left" ? leftFixedOffsets.get(columnIndex) ?? 0 : getScrollableColumnLeft(columnIndex)) : null),
|
|
4549
4642
|
headerCells.map((cell) => columns[cell.startIndex]?.fixed ? renderGroupedHeaderCell(cell) : null),
|
|
4550
4643
|
fixedWidth > 0 && currentScroll.left > 0 && /* @__PURE__ */ jsx7("div", { className: "rvg-text-fixed-shadow is-left", style: { left: fixedWidth } }),
|
|
4551
4644
|
rightFixedWidth > 0 && currentScroll.left < contentWidth - viewport.width && /* @__PURE__ */ jsx7("div", { className: "rvg-text-fixed-shadow is-right", style: { right: rightFixedWidth } }),
|
|
@@ -4762,7 +4855,7 @@ function Table({
|
|
|
4762
4855
|
const affectedRows = selectedIndices.includes(cell.rowIndex) ? selectedIndices : [cell.rowIndex];
|
|
4763
4856
|
const cellContext = { ...cell, row, column, value: dataIndex === void 0 ? void 0 : row[dataIndex] };
|
|
4764
4857
|
return renderConfiguredContextMenu(resolveContextMenuSection(customContextMenuConfig?.cell, DEFAULT_CELL_CONTEXT_MENU), cellContext, (item, override) => {
|
|
4765
|
-
if (item === "edit") return renderContextMenuButton("cell-edit", cellContext, labels.edit, () => beginEdit(cell), override, { disabled: !
|
|
4858
|
+
if (item === "edit") return renderContextMenuButton("cell-edit", cellContext, labels.edit, () => beginEdit(cell), override, { disabled: !isCellEditable(cell), icon: /* @__PURE__ */ jsx7(ContextMenuIcon, { type: "edit" }) });
|
|
4766
4859
|
if (item === "copy") return renderContextMenuButton("cell-copy", cellContext, labels.copyContent, async () => {
|
|
4767
4860
|
try {
|
|
4768
4861
|
await navigator.clipboard.writeText(getCellLabel(cell.rowIndex, cell.columnIndex));
|
|
@@ -5002,6 +5095,7 @@ function Table({
|
|
|
5002
5095
|
loading && !hasCustomLoading && hasCompletedLoadRef.current && /* @__PURE__ */ jsx7("div", { className: "rvg-refresh-loading", "aria-label": labels.refreshing, children: /* @__PURE__ */ jsx7(LoadingSpinnerIcon, {}) })
|
|
5003
5096
|
] });
|
|
5004
5097
|
}
|
|
5098
|
+
var Table = forwardRef(TableInner);
|
|
5005
5099
|
export {
|
|
5006
5100
|
Table,
|
|
5007
5101
|
Table as VelocityGrid,
|