@lensui/lens-table 0.1.11 → 0.1.13
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 +2 -1
- package/dist/index.cjs +95 -52
- package/dist/index.css +8 -2
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +95 -52
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ export function Example() {
|
|
|
89
89
|
| `rowKey` | `keyof Row \| ((row, index) => string \| number)` | `id` | 行唯一标识。默认读取每行的`id` 字段;如果数据不是 `id` 主键,请显式传入字段名或函数。 |
|
|
90
90
|
| `width` | `number \| string` | `100%` | 表格宽度。数字按像素处理,字符串可传`100%`、`80vw` 等。 |
|
|
91
91
|
| `height` | `number \| string` | `100%` | 表格最大高度。默认继承父容器高度;如果父容器没有可计算高度,则回落到`480px`。数据较少时默认按真实内容高度收缩,数据较多时不超过该高度。 |
|
|
92
|
-
| `layout` | `{ rowHeight?: number; headerHeight?: number }`
|
|
92
|
+
| `layout` | `{ rowHeight?: number; headerHeight?: number; headerActionSize?: number }` | `{ rowHeight: 36, headerHeight: 40, headerActionSize: 14 }` | 表格布局尺寸配置。`headerActionSize` 同步控制表头搜索、排序和拖拽图标的尺寸、占位及点击区域;自定义多行表头会以 `headerHeight` 为最小高度自动撑开。 |
|
|
93
93
|
| `rowHeight` | `number` | `36` | 已兼容保留,建议改用 `layout.rowHeight`。 |
|
|
94
94
|
| `headerHeight` | `number` | `40` | 已兼容保留,建议改用 `layout.headerHeight`。 |
|
|
95
95
|
| `fixedHeader` | `boolean` | `true` | 表头是否固定在顶部。 |
|
|
@@ -97,6 +97,7 @@ export function Example() {
|
|
|
97
97
|
| `borderless` | `boolean` | `false` | 是否弱化竖向边框。开启后隐藏单元格之间的竖线,但保留横向分隔线。 |
|
|
98
98
|
| `verticalBorderless` | `boolean` | `false` | 已兼容保留,建议改用 `borderless`。 |
|
|
99
99
|
| `horizontalBorderless` | `boolean` | `false` | 是否隐藏横向行分隔线及上下边框,同时保留纵向列分隔线。可与 `striped` 配合使用。 |
|
|
100
|
+
| `frameBorderless` | `boolean` | `false` | 是否隐藏表格四周外框,同时保留内部行列分隔线。 |
|
|
100
101
|
| `striped` | `boolean \| string` | `false` | 是否显示斑马纹行背景。传`true` 使用主题变量,传颜色字符串可自定义斑马纹颜色,例如 `'#f6faff'`。 |
|
|
101
102
|
| `highlight` | `{ editedCells?: boolean \| string; insertedRows?: boolean \| string }` | `{}` | 高亮反馈配置。`editedCells` 控制编辑过的单元格底色,`insertedRows` 控制乐观插入行底色;传 `true` 使用默认色,传颜色字符串可自定义。 |
|
|
102
103
|
| `cellSpans` | `TableCellSpan[] \| ((ctx) => TableCellSpan \| { rowSpan?: number; colSpan?: number } \| null)` | `[]` | 合并主体单元格配置。可传数组,也可传函数按单元格生成规则。推荐使用 `rowKey` 定位;横向合并会限制在同一个固定列分区内,工具列不会参与合并。 |
|
package/dist/index.cjs
CHANGED
|
@@ -822,8 +822,8 @@ function getHeaderTitleRequiredWidth(column, titleWidth) {
|
|
|
822
822
|
const minimumReadableTitleWidth = Math.min(Math.ceil(titleWidth), 28);
|
|
823
823
|
return minimumReadableTitleWidth + (column.align === "center" ? 20 : 22);
|
|
824
824
|
}
|
|
825
|
-
function getVisibleHeaderActions(column, width, columnDraggable = false, titleWidth = 26) {
|
|
826
|
-
const capacity = Math.max(0, Math.floor((width - getHeaderTitleRequiredWidth(column, titleWidth)) /
|
|
825
|
+
function getVisibleHeaderActions(column, width, columnDraggable = false, titleWidth = 26, actionSlotWidth = HEADER_ACTION_SLOT_WIDTH) {
|
|
826
|
+
const capacity = Math.max(0, Math.floor((width - getHeaderTitleRequiredWidth(column, titleWidth)) / actionSlotWidth));
|
|
827
827
|
const candidates = [
|
|
828
828
|
isColumnFilterable(column) ? "filter" : null,
|
|
829
829
|
isColumnSortable(column) ? "sort" : null,
|
|
@@ -942,7 +942,7 @@ function ellipsizeText(context, text, maxWidth) {
|
|
|
942
942
|
return `${text.slice(0, start)}${ellipsis}`;
|
|
943
943
|
}
|
|
944
944
|
function paintGrid(options) {
|
|
945
|
-
const { context: ctx, width, height, pixelRatio, scrollLeft, scrollTop, rowHeight, bodyFontSize, headerHeight, fixedHeader, verticalBorderless, horizontalBorderless, striped, columnDraggable, sortState, filterValues, hoveredHeaderAction, rows, columns, metrics, range, selection, editing, hoveredRowIndex, selectionRange, selectedRowKeys, rowSelectionMode, selectedColumnKeys, highlightEditedCells, highlightInsertedRows, insertedRowKeys, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview, columnDropTarget } = options;
|
|
945
|
+
const { context: ctx, width, height, pixelRatio, scrollLeft, scrollTop, rowHeight, bodyFontSize, headerActionSlotWidth, headerHeight, fixedHeader, verticalBorderless, horizontalBorderless, frameBorderless, extendVerticalGridLines, striped, columnDraggable, sortState, filterValues, hoveredHeaderAction, rows, columns, metrics, range, selection, editing, hoveredRowIndex, selectionRange, selectedRowKeys, rowSelectionMode, selectedColumnKeys, highlightEditedCells, highlightInsertedRows, insertedRowKeys, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview, columnDropTarget } = options;
|
|
946
946
|
const headerLeafTop = options.headerLeafTop ?? 0;
|
|
947
947
|
const headerLeafHeight = options.headerLeafHeight ?? headerHeight;
|
|
948
948
|
const colors = { ...COLORS, ...options.colors };
|
|
@@ -1063,7 +1063,9 @@ function paintGrid(options) {
|
|
|
1063
1063
|
ctx.fillRect(x, y, cellWidth, cellHeight);
|
|
1064
1064
|
}
|
|
1065
1065
|
ctx.fillStyle = colors.grid;
|
|
1066
|
-
if (!verticalBorderless
|
|
1066
|
+
if (!verticalBorderless && !(frameBorderless && columnIndex + colSpan >= columns.length)) {
|
|
1067
|
+
ctx.fillRect(x + cellWidth - 1, y, 1, cellHeight);
|
|
1068
|
+
}
|
|
1067
1069
|
if (rowIndex === rowBelowDragGap) ctx.fillRect(x, y, cellWidth, 1);
|
|
1068
1070
|
if (!horizontalBorderless && (!options.suppressLastRowBottomBorder || rowIndex !== rows.length - 1)) {
|
|
1069
1071
|
ctx.fillRect(x, y + cellHeight - 1, cellWidth, 1);
|
|
@@ -1182,6 +1184,30 @@ function paintGrid(options) {
|
|
|
1182
1184
|
paintBodyColumns("scroll");
|
|
1183
1185
|
paintBodyColumns("left");
|
|
1184
1186
|
paintBodyColumns("right");
|
|
1187
|
+
if (extendVerticalGridLines && !verticalBorderless) {
|
|
1188
|
+
const extensionTop = Math.max(bodyTop, Math.min(height, bodyTop + rows.length * rowHeight - scrollTop));
|
|
1189
|
+
const extensionHeight = Math.max(0, height - extensionTop);
|
|
1190
|
+
const paintExtendedColumnLines = (layer) => {
|
|
1191
|
+
ctx.save();
|
|
1192
|
+
if (layer === "scroll") {
|
|
1193
|
+
ctx.beginPath();
|
|
1194
|
+
ctx.rect(leftFixedWidth, extensionTop, Math.max(0, rightFixedLeft - leftFixedWidth), extensionHeight);
|
|
1195
|
+
ctx.clip();
|
|
1196
|
+
}
|
|
1197
|
+
ctx.fillStyle = colors.grid;
|
|
1198
|
+
for (let columnIndex = 0; columnIndex < columns.length; columnIndex += 1) {
|
|
1199
|
+
if (layer === "scroll" ? columns[columnIndex].fixed !== void 0 : columns[columnIndex].fixed !== layer) continue;
|
|
1200
|
+
if (layer === "scroll" && (columnIndex < range.columnStart || columnIndex >= range.columnEnd)) continue;
|
|
1201
|
+
if (frameBorderless && columnIndex === columns.length - 1) continue;
|
|
1202
|
+
const x = getColumnX(columnIndex) + metrics[columnIndex].width - 1;
|
|
1203
|
+
ctx.fillRect(x, extensionTop, 1, extensionHeight);
|
|
1204
|
+
}
|
|
1205
|
+
ctx.restore();
|
|
1206
|
+
};
|
|
1207
|
+
paintExtendedColumnLines("scroll");
|
|
1208
|
+
paintExtendedColumnLines("left");
|
|
1209
|
+
paintExtendedColumnLines("right");
|
|
1210
|
+
}
|
|
1185
1211
|
const headerY = fixedHeader ? 0 : -scrollTop;
|
|
1186
1212
|
ctx.fillStyle = colors.header;
|
|
1187
1213
|
ctx.fillRect(0, headerY, width, headerHeight);
|
|
@@ -1205,14 +1231,16 @@ function paintGrid(options) {
|
|
|
1205
1231
|
ctx.fillRect(x, headerY, metric.width, headerHeight);
|
|
1206
1232
|
}
|
|
1207
1233
|
ctx.fillStyle = colors.grid;
|
|
1208
|
-
if (!verticalBorderless
|
|
1234
|
+
if (!verticalBorderless && !(frameBorderless && columnIndex === columns.length - 1)) {
|
|
1235
|
+
ctx.fillRect(x + metric.width - 1, headerY, 1, headerHeight);
|
|
1236
|
+
}
|
|
1209
1237
|
if (!horizontalBorderless) ctx.fillRect(x, headerY + headerHeight - 1, metric.width, 1);
|
|
1210
1238
|
const column = columns[columnIndex];
|
|
1211
1239
|
if (headerLeafTop === 0 && !column.rowSelection && !column.rowDragHandle && !column.rowNumber && !column.renderHeader && column.title) {
|
|
1212
1240
|
ctx.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
1213
1241
|
const titleWidth = ctx.measureText(column.title).width;
|
|
1214
|
-
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth);
|
|
1215
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
1242
|
+
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth, headerActionSlotWidth);
|
|
1243
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth;
|
|
1216
1244
|
const contentWidth = Math.max(0, metric.width - actionWidth);
|
|
1217
1245
|
const padding = 10;
|
|
1218
1246
|
const clipWidth = contentWidth;
|
|
@@ -1242,12 +1270,12 @@ function paintGrid(options) {
|
|
|
1242
1270
|
ctx.fillRect(rightFixedLeft - 1, 0, 1, height);
|
|
1243
1271
|
}
|
|
1244
1272
|
ctx.fillStyle = colors.grid;
|
|
1245
|
-
if (!horizontalBorderless) ctx.fillRect(0, 0, width, 1);
|
|
1246
|
-
if (!verticalBorderless) {
|
|
1273
|
+
if (!horizontalBorderless && !frameBorderless) ctx.fillRect(0, 0, width, 1);
|
|
1274
|
+
if (!verticalBorderless && !frameBorderless) {
|
|
1247
1275
|
ctx.fillRect(0, 0, 1, height);
|
|
1248
1276
|
ctx.fillRect(width - 1, 0, 1, height);
|
|
1249
1277
|
}
|
|
1250
|
-
if (!horizontalBorderless && !options.suppressFrameBottomBorder) ctx.fillRect(0, height - 1, width, 1);
|
|
1278
|
+
if (!horizontalBorderless && !frameBorderless && !options.suppressFrameBottomBorder) ctx.fillRect(0, height - 1, width, 1);
|
|
1251
1279
|
if (selectionRange) {
|
|
1252
1280
|
const rowStart = Math.min(selectionRange.anchor.rowIndex, selectionRange.focus.rowIndex);
|
|
1253
1281
|
const rowEnd = Math.max(selectionRange.anchor.rowIndex, selectionRange.focus.rowIndex);
|
|
@@ -1556,6 +1584,7 @@ function TableInner({
|
|
|
1556
1584
|
borderless,
|
|
1557
1585
|
verticalBorderless,
|
|
1558
1586
|
horizontalBorderless = false,
|
|
1587
|
+
frameBorderless = false,
|
|
1559
1588
|
striped = false,
|
|
1560
1589
|
highlight,
|
|
1561
1590
|
cellSpans = [],
|
|
@@ -1602,6 +1631,8 @@ function TableInner({
|
|
|
1602
1631
|
setSourceColumns((current) => reconcileColumns(current, columnProps));
|
|
1603
1632
|
}, [columnProps]);
|
|
1604
1633
|
const rowHeight = layout?.rowHeight ?? rowHeightProp ?? 36;
|
|
1634
|
+
const headerActionSize = Math.max(8, layout?.headerActionSize ?? 14);
|
|
1635
|
+
const headerActionSlotWidth = headerActionSize + 2;
|
|
1605
1636
|
const baseHeaderHeight = layout?.headerHeight ?? headerHeightProp ?? 40;
|
|
1606
1637
|
const headerDepth = (0, import_react5.useMemo)(() => Math.max(1, ...sourceColumns.map(getColumnDepth)), [sourceColumns]);
|
|
1607
1638
|
const { language, labels } = (0, import_react5.useMemo)(() => resolveGridLocale(locale), [locale]);
|
|
@@ -2237,8 +2268,8 @@ function TableInner({
|
|
|
2237
2268
|
const scroll = scrollRef.current;
|
|
2238
2269
|
const rowScrollTop = fixedHeader ? scroll.top : Math.max(0, scroll.top - bodyTop);
|
|
2239
2270
|
const range = isVirtualized ? getViewportRange(scroll.left, rowScrollTop, viewport.width, bodyViewportHeight, rows.length, rowHeight, metrics, virtualOverscan) : { rowStart: 0, rowEnd: rows.length, columnStart: 0, columnEnd: columns.length };
|
|
2240
|
-
paintGrid({ context, width: viewport.width, height: renderHeight, pixelRatio: ratio, scrollLeft: scroll.left, scrollTop: scroll.top, rowHeight, bodyFontSize, headerHeight, headerLeafTop, headerLeafHeight, bodyTop, suppressLastRowBottomBorder: bottomSummaryHeight > 0, suppressFrameBottomBorder: bottomSummaryHeight > 0, fixedHeader, verticalBorderless: !hasVerticalBorders, horizontalBorderless, striped: hasStripedRows, columnDraggable, sortState, filterValues, hoveredHeaderAction: hoveredHeaderActionRef.current, rows, columns, metrics, range, selection, editing, hoveredRowIndex: hoveredRowIndexRef.current, selectionRange, selectedRowKeys: selectedRowKeySet, rowSelectionMode, selectedColumnKeys: selectedColumnKeySet, cellSpans: cellSpanLookup.covered, maxRowSpan: cellSpanLookup.maxRowSpan, highlightEditedCells: highlightsEditedCells, highlightInsertedRows: highlightsInsertedRows, insertedRowKeys: insertedRowKeySet, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview, columnDropTarget, colors: themeColors });
|
|
2241
|
-
}, [bodyTop, bodyViewportHeight, bottomSummaryHeight, cellAnnotations, cellSpanLookup, columnDraggable, columnDropTarget, columns, editedCellHighlightColor, editedCellKeys, editing, renderHeight, filterValues, fixedHeader, getRowKey, hasStripedRows, hasVerticalBorders, headerDepth, headerHeight, headerLeafHeight, headerLeafTop, horizontalBorderless, highlightsEditedCells, highlightsInsertedRows, insertedRowHighlightColor, insertedRowKeySet, isVirtualized, metrics, rowDragPreview, rowHeight, rowSelectionMode, rows, selectedColumnKeySet, selectedRowKeySet, selection, selectionRange, sortState, stripedColor, viewport.width, virtualOverscan]);
|
|
2271
|
+
paintGrid({ context, width: viewport.width, height: renderHeight, pixelRatio: ratio, scrollLeft: scroll.left, scrollTop: scroll.top, rowHeight, bodyFontSize, headerActionSlotWidth, headerHeight, headerLeafTop, headerLeafHeight, bodyTop, suppressLastRowBottomBorder: bottomSummaryHeight > 0, suppressFrameBottomBorder: bottomSummaryHeight > 0, fixedHeader, verticalBorderless: !hasVerticalBorders, horizontalBorderless, frameBorderless, extendVerticalGridLines: !autoHeight, striped: hasStripedRows, columnDraggable, sortState, filterValues, hoveredHeaderAction: hoveredHeaderActionRef.current, rows, columns, metrics, range, selection, editing, hoveredRowIndex: hoveredRowIndexRef.current, selectionRange, selectedRowKeys: selectedRowKeySet, rowSelectionMode, selectedColumnKeys: selectedColumnKeySet, cellSpans: cellSpanLookup.covered, maxRowSpan: cellSpanLookup.maxRowSpan, highlightEditedCells: highlightsEditedCells, highlightInsertedRows: highlightsInsertedRows, insertedRowKeys: insertedRowKeySet, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview, columnDropTarget, colors: themeColors });
|
|
2272
|
+
}, [autoHeight, bodyTop, bodyViewportHeight, bottomSummaryHeight, cellAnnotations, cellSpanLookup, columnDraggable, columnDropTarget, columns, editedCellHighlightColor, editedCellKeys, editing, renderHeight, filterValues, fixedHeader, frameBorderless, getRowKey, hasStripedRows, hasVerticalBorders, headerActionSlotWidth, headerDepth, headerHeight, headerLeafHeight, headerLeafTop, horizontalBorderless, highlightsEditedCells, highlightsInsertedRows, insertedRowHighlightColor, insertedRowKeySet, isVirtualized, metrics, rowDragPreview, rowHeight, rowSelectionMode, rows, selectedColumnKeySet, selectedRowKeySet, selection, selectionRange, sortState, stripedColor, viewport.width, virtualOverscan]);
|
|
2242
2273
|
const scheduleDraw = (0, import_react5.useCallback)(() => {
|
|
2243
2274
|
if (frameRef.current === null) frameRef.current = requestAnimationFrame(draw);
|
|
2244
2275
|
}, [draw]);
|
|
@@ -2804,34 +2835,34 @@ function TableInner({
|
|
|
2804
2835
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
|
|
2805
2836
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2806
2837
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2807
|
-
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
2808
|
-
let right = columnRight - (visibleActions.drag ?
|
|
2838
|
+
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
2839
|
+
let right = columnRight - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
2809
2840
|
if (visibleActions.sort) {
|
|
2810
|
-
if (localX >= right -
|
|
2811
|
-
right -=
|
|
2841
|
+
if (localX >= right - headerActionSlotWidth && localX < right) return "sort";
|
|
2842
|
+
right -= headerActionSlotWidth;
|
|
2812
2843
|
}
|
|
2813
|
-
if (visibleActions.filter && localX >= right -
|
|
2844
|
+
if (visibleActions.filter && localX >= right - headerActionSlotWidth && localX < right) return "filter";
|
|
2814
2845
|
return null;
|
|
2815
|
-
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2846
|
+
}, [columnDraggable, columns, getDisplayedColumnLeft, headerActionSlotWidth, measureHeaderTitleWidth, metrics]);
|
|
2816
2847
|
const isHeaderTitleTruncated = (0, import_react5.useCallback)((columnIndex) => {
|
|
2817
2848
|
const canvas = canvasRef.current;
|
|
2818
2849
|
if (columnIndex < 0 || !canvas) return false;
|
|
2819
2850
|
const column = columns[columnIndex];
|
|
2820
2851
|
const metric = metrics[columnIndex];
|
|
2821
2852
|
const titleWidth = measureHeaderTitleWidth(columnIndex);
|
|
2822
|
-
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth);
|
|
2823
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
2853
|
+
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth, headerActionSlotWidth);
|
|
2854
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth;
|
|
2824
2855
|
return getHeaderTitleRequiredWidth(column, titleWidth) > Math.max(0, metric.width - actionWidth);
|
|
2825
|
-
}, [columnDraggable, columns, measureHeaderTitleWidth, metrics]);
|
|
2856
|
+
}, [columnDraggable, columns, headerActionSlotWidth, measureHeaderTitleWidth, metrics]);
|
|
2826
2857
|
const locateHeaderDragHandle = (0, import_react5.useCallback)((clientX, columnIndex) => {
|
|
2827
2858
|
if (!columnDraggable || columnIndex < 0 || !canvasRef.current) return false;
|
|
2828
2859
|
const column = columns[columnIndex];
|
|
2829
2860
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return false;
|
|
2830
|
-
if (!getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex)).drag) return false;
|
|
2861
|
+
if (!getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth).drag) return false;
|
|
2831
2862
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2832
2863
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2833
|
-
return localX >= columnRight -
|
|
2834
|
-
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2864
|
+
return localX >= columnRight - headerActionSlotWidth && localX < columnRight - 2;
|
|
2865
|
+
}, [columnDraggable, columns, getDisplayedColumnLeft, headerActionSlotWidth, measureHeaderTitleWidth, metrics]);
|
|
2835
2866
|
const getHeaderCellLeft = (0, import_react5.useCallback)((cell) => {
|
|
2836
2867
|
const startMetric = metrics[cell.startIndex];
|
|
2837
2868
|
const fixedSide = columns[cell.startIndex]?.fixed;
|
|
@@ -2896,8 +2927,8 @@ function TableInner({
|
|
|
2896
2927
|
if (cell.leaf) return locateHeaderDragHandle(clientX, cell.startIndex);
|
|
2897
2928
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2898
2929
|
const right = getHeaderCellLeft(cell) + getHeaderCellWidth(cell);
|
|
2899
|
-
return localX >= right -
|
|
2900
|
-
}, [columnDraggable, getHeaderCellLeft, getHeaderCellWidth, locateHeaderDragHandle]);
|
|
2930
|
+
return localX >= right - headerActionSlotWidth && localX < right - 2;
|
|
2931
|
+
}, [columnDraggable, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, locateHeaderDragHandle]);
|
|
2901
2932
|
const locateHeaderCell = (0, import_react5.useCallback)((clientX, clientY) => {
|
|
2902
2933
|
const canvas = canvasRef.current;
|
|
2903
2934
|
if (!canvas) return null;
|
|
@@ -3053,26 +3084,32 @@ function TableInner({
|
|
|
3053
3084
|
header.style.height = `${headerHeight}px`;
|
|
3054
3085
|
header.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
|
|
3055
3086
|
header.textContent = column.title;
|
|
3056
|
-
const visibleActions = getVisibleHeaderActions(column, columnWidth, columnDraggable, measureHeaderTitleWidth(sourceIndex));
|
|
3087
|
+
const visibleActions = getVisibleHeaderActions(column, columnWidth, columnDraggable, measureHeaderTitleWidth(sourceIndex), headerActionSlotWidth);
|
|
3057
3088
|
let actionRight = 2;
|
|
3058
3089
|
if (visibleActions.drag) {
|
|
3059
3090
|
const icon = createHeaderDragHandleSvg();
|
|
3060
3091
|
icon.classList.add("rvg-preview-header-icon");
|
|
3092
|
+
icon.style.width = `${headerActionSize}px`;
|
|
3093
|
+
icon.style.height = `${headerActionSize}px`;
|
|
3061
3094
|
icon.style.right = `${actionRight}px`;
|
|
3062
3095
|
header.appendChild(icon);
|
|
3063
|
-
actionRight +=
|
|
3096
|
+
actionRight += headerActionSlotWidth;
|
|
3064
3097
|
}
|
|
3065
3098
|
if (visibleActions.sort) {
|
|
3066
3099
|
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3067
3100
|
const icon = createHeaderSortSvg(direction);
|
|
3068
3101
|
icon.classList.add("rvg-preview-header-icon");
|
|
3102
|
+
icon.style.width = `${headerActionSize}px`;
|
|
3103
|
+
icon.style.height = `${headerActionSize}px`;
|
|
3069
3104
|
icon.style.right = `${actionRight}px`;
|
|
3070
3105
|
header.appendChild(icon);
|
|
3071
|
-
actionRight +=
|
|
3106
|
+
actionRight += headerActionSlotWidth;
|
|
3072
3107
|
}
|
|
3073
3108
|
if (visibleActions.filter) {
|
|
3074
3109
|
const icon = createHeaderSearchSvg(Boolean(filterValues[column.key]));
|
|
3075
3110
|
icon.classList.add("rvg-preview-header-icon", "rvg-preview-header-search-icon");
|
|
3111
|
+
icon.style.width = `${headerActionSize}px`;
|
|
3112
|
+
icon.style.height = `${headerActionSize}px`;
|
|
3076
3113
|
icon.style.right = `${actionRight}px`;
|
|
3077
3114
|
header.appendChild(icon);
|
|
3078
3115
|
}
|
|
@@ -3269,7 +3306,7 @@ function TableInner({
|
|
|
3269
3306
|
cleanupDrag();
|
|
3270
3307
|
cleanupDrop();
|
|
3271
3308
|
};
|
|
3272
|
-
}, [applyColumnOrder, applyRowOrder, bodyTop, columnDraggable, columns, filterValues, fixedHeader, getCellLabel, getDisplayedColumnLeft, getHeaderCellWidth, getRowKey, headerCells, headerHeight, hideDragTooltips, locateColumn, locateHeaderCell, locateHeaderCellDragHandle, locateHeaderResizeCell, locateRow, measureHeaderTitleWidth, metrics, rowDraggable, rowHeight, rows, selectedRowKeySet, selection, setDragGuide, setRowDragGuide, sortState, utilityColumnCount]);
|
|
3309
|
+
}, [applyColumnOrder, applyRowOrder, bodyTop, columnDraggable, columns, filterValues, fixedHeader, getCellLabel, getDisplayedColumnLeft, getHeaderCellWidth, getRowKey, headerActionSize, headerActionSlotWidth, headerCells, headerHeight, hideDragTooltips, locateColumn, locateHeaderCell, locateHeaderCellDragHandle, locateHeaderResizeCell, locateRow, measureHeaderTitleWidth, metrics, rowDraggable, rowHeight, rows, selectedRowKeySet, selection, setDragGuide, setRowDragGuide, sortState, utilityColumnCount]);
|
|
3273
3310
|
const locateCell = (0, import_react5.useCallback)((clientX, clientY) => {
|
|
3274
3311
|
const canvas = canvasRef.current;
|
|
3275
3312
|
if (!canvas) return null;
|
|
@@ -3713,28 +3750,28 @@ function TableInner({
|
|
|
3713
3750
|
const renderHeaderIcons = (columnIndex, left) => {
|
|
3714
3751
|
const column = columns[columnIndex];
|
|
3715
3752
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
|
|
3716
|
-
const top = headerLeafTop + (headerLeafHeight -
|
|
3717
|
-
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
3718
|
-
let right = left + metrics[columnIndex].width - (visibleActions.drag ?
|
|
3753
|
+
const top = headerLeafTop + (headerLeafHeight - headerActionSize) / 2;
|
|
3754
|
+
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
3755
|
+
let right = left + metrics[columnIndex].width - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
3719
3756
|
const icons = [];
|
|
3720
3757
|
if (visibleActions.drag) {
|
|
3721
3758
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "drag";
|
|
3722
3759
|
icons.push(
|
|
3723
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HeaderDragIcon, { className: `rvg-header-icon rvg-header-drag-icon${hovered ? " is-hovered" : ""}`, style: { left: left + metrics[columnIndex].width -
|
|
3760
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HeaderDragIcon, { className: `rvg-header-icon rvg-header-drag-icon${hovered ? " is-hovered" : ""}`, style: { left: left + metrics[columnIndex].width - headerActionSlotWidth, top } }, "drag")
|
|
3724
3761
|
);
|
|
3725
3762
|
}
|
|
3726
3763
|
if (visibleActions.sort) {
|
|
3727
3764
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "sort";
|
|
3728
3765
|
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3729
3766
|
icons.push(
|
|
3730
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HeaderSortIcon, { className: `rvg-header-icon${hovered ? " is-hovered" : ""}`, style: { left: right -
|
|
3767
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HeaderSortIcon, { className: `rvg-header-icon${hovered ? " is-hovered" : ""}`, style: { left: right - headerActionSlotWidth, top }, direction }, "sort")
|
|
3731
3768
|
);
|
|
3732
|
-
right -=
|
|
3769
|
+
right -= headerActionSlotWidth;
|
|
3733
3770
|
}
|
|
3734
3771
|
if (visibleActions.filter) {
|
|
3735
3772
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "filter";
|
|
3736
3773
|
icons.push(
|
|
3737
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HeaderSearchIcon, { className: `rvg-header-icon rvg-header-search-icon${hovered ? " is-hovered" : ""}${filterValues[column.key] ? " is-active" : ""}`, style: { left: right -
|
|
3774
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HeaderSearchIcon, { className: `rvg-header-icon rvg-header-search-icon${hovered ? " is-hovered" : ""}${filterValues[column.key] ? " is-active" : ""}`, style: { left: right - headerActionSlotWidth, top: top + 1 } }, "filter")
|
|
3738
3775
|
);
|
|
3739
3776
|
}
|
|
3740
3777
|
return icons;
|
|
@@ -3755,8 +3792,8 @@ function TableInner({
|
|
|
3755
3792
|
const context = canvas?.getContext("2d");
|
|
3756
3793
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3757
3794
|
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3758
|
-
const visibleActions = cell?.leaf || !cell ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3759
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
3795
|
+
const visibleActions = cell?.leaf || !cell ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth, headerActionSlotWidth) : null;
|
|
3796
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth : columnDraggable ? headerActionSlotWidth : 0;
|
|
3760
3797
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3761
3798
|
const maxTextWidth = Math.max(0, contentWidth2 - 20);
|
|
3762
3799
|
const textWidth = Math.min(titleWidth, maxTextWidth);
|
|
@@ -3777,12 +3814,17 @@ function TableInner({
|
|
|
3777
3814
|
} else if (action === "sort") {
|
|
3778
3815
|
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3779
3816
|
label = direction === "asc" ? labels.sortAsc : direction === "desc" ? labels.sortDesc : labels.sortBoth;
|
|
3780
|
-
|
|
3817
|
+
const visibleActions = getVisibleHeaderActions(column, cellWidth, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
3818
|
+
const right = cellLeft + cellWidth - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
3819
|
+
anchorX = right - headerActionSlotWidth / 2;
|
|
3781
3820
|
anchorLeft = anchorX;
|
|
3782
3821
|
} else if (action === "filter") {
|
|
3783
3822
|
const value = filterValues[column.key];
|
|
3784
3823
|
label = value ? labels.filterWithValue(value) : labels.filter;
|
|
3785
|
-
|
|
3824
|
+
const visibleActions = getVisibleHeaderActions(column, cellWidth, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
3825
|
+
let right = cellLeft + cellWidth - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
3826
|
+
if (visibleActions.sort) right -= headerActionSlotWidth;
|
|
3827
|
+
anchorX = right - headerActionSlotWidth / 2;
|
|
3786
3828
|
anchorLeft = anchorX;
|
|
3787
3829
|
}
|
|
3788
3830
|
const placement = anchorX + 328 > viewport.width ? "left" : "right";
|
|
@@ -3795,7 +3837,7 @@ function TableInner({
|
|
|
3795
3837
|
label,
|
|
3796
3838
|
placement
|
|
3797
3839
|
};
|
|
3798
|
-
}, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, metrics, scrollPosition.top, sortState, viewport.width]);
|
|
3840
|
+
}, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, measureHeaderTitleWidth, metrics, scrollPosition.top, sortState, viewport.width]);
|
|
3799
3841
|
const isPointerOnHeaderTitle = (0, import_react5.useCallback)((clientX, clientY, cell) => {
|
|
3800
3842
|
const canvas = canvasRef.current;
|
|
3801
3843
|
if (!canvas) return false;
|
|
@@ -3809,14 +3851,14 @@ function TableInner({
|
|
|
3809
3851
|
const context = canvas.getContext("2d");
|
|
3810
3852
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3811
3853
|
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3812
|
-
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3813
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
3854
|
+
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth, headerActionSlotWidth) : null;
|
|
3855
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth : columnDraggable ? headerActionSlotWidth : 0;
|
|
3814
3856
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3815
3857
|
const textWidth = Math.min(titleWidth, Math.max(0, contentWidth2 - 20));
|
|
3816
3858
|
const textLeft = column.align === "right" ? cellLeft + contentWidth2 - 10 - textWidth : column.align === "center" ? cellLeft + contentWidth2 / 2 - textWidth / 2 : cellLeft + 10;
|
|
3817
3859
|
const textTop = rowTop + 8;
|
|
3818
3860
|
return localX >= textLeft - 4 && localX <= textLeft + textWidth + 4 && localY >= textTop - 2 && localY <= textTop + 18;
|
|
3819
|
-
}, [columnDraggable, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerRowOffsets]);
|
|
3861
|
+
}, [columnDraggable, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, headerRowOffsets]);
|
|
3820
3862
|
const headerTooltip = (() => {
|
|
3821
3863
|
if (!visibleHeaderTooltip) return null;
|
|
3822
3864
|
return visibleHeaderTooltip;
|
|
@@ -4139,8 +4181,8 @@ function TableInner({
|
|
|
4139
4181
|
);
|
|
4140
4182
|
}
|
|
4141
4183
|
if (column.renderHeader) {
|
|
4142
|
-
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
4143
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
4184
|
+
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
4185
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth;
|
|
4144
4186
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4145
4187
|
"div",
|
|
4146
4188
|
{
|
|
@@ -4184,13 +4226,13 @@ function TableInner({
|
|
|
4184
4226
|
const headerTop = (fixedHeader ? 0 : -currentScrollTop) + (headerRowOffsets[cell.level] ?? 0);
|
|
4185
4227
|
const left = fixedSide === "left" ? leftFixedOffsets.get(cell.startIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(cell.startIndex) ?? 0) - startMetric.width : getScrollableColumnLeft(cell.startIndex);
|
|
4186
4228
|
const width2 = cell.leaf ? startMetric.width : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1);
|
|
4187
|
-
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, startMetric.width, columnDraggable, measureHeaderTitleWidth(cell.startIndex)) : null;
|
|
4188
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
4229
|
+
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, startMetric.width, columnDraggable, measureHeaderTitleWidth(cell.startIndex), headerActionSlotWidth) : null;
|
|
4230
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth : columnDraggable && !cell.leaf ? headerActionSlotWidth : 0;
|
|
4189
4231
|
const isDropTarget = Boolean(columnDropTarget && cell.endIndex >= columnDropTarget.startIndex && cell.startIndex <= columnDropTarget.endIndex);
|
|
4190
4232
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
4191
4233
|
"div",
|
|
4192
4234
|
{
|
|
4193
|
-
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}${isDropTarget ? " is-drop-target" : ""}`,
|
|
4235
|
+
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}${cell.endIndex === columns.length - 1 ? " is-frame-right" : ""}${isDropTarget ? " is-drop-target" : ""}`,
|
|
4194
4236
|
"data-level": cell.level,
|
|
4195
4237
|
"data-measure-key": `group:${cell.key}:${cell.level}`,
|
|
4196
4238
|
style: {
|
|
@@ -4221,7 +4263,7 @@ function TableInner({
|
|
|
4221
4263
|
HeaderDragIcon,
|
|
4222
4264
|
{
|
|
4223
4265
|
className: `rvg-header-icon rvg-header-drag-icon${hoveredHeaderAction?.columnIndex === cell.startIndex && hoveredHeaderAction.action === "drag" ? " is-hovered" : ""}`,
|
|
4224
|
-
style: { left: width2 -
|
|
4266
|
+
style: { left: width2 - headerActionSlotWidth, top: (rowHeightForLevel - headerActionSize) / 2 }
|
|
4225
4267
|
}
|
|
4226
4268
|
)
|
|
4227
4269
|
]
|
|
@@ -4487,12 +4529,13 @@ function TableInner({
|
|
|
4487
4529
|
width,
|
|
4488
4530
|
height: autoHeight ? effectiveHeight : height,
|
|
4489
4531
|
minHeight: autoHeight || typeof height === "number" ? void 0 : FALLBACK_HEIGHT,
|
|
4532
|
+
"--rvg-header-action-size": `${headerActionSize}px`,
|
|
4490
4533
|
...stripedColor ? { "--rvg-color-stripe": stripedColor } : null,
|
|
4491
4534
|
...style
|
|
4492
4535
|
};
|
|
4493
4536
|
const currentScroll = scrollRef.current;
|
|
4494
4537
|
const scrollerBottom = Math.max(0, bottomSummaryHeight - horizontalScrollbarHeight);
|
|
4495
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `rvg-root${!hasVerticalBorders ? " is-vertical-borderless" : ""}${horizontalBorderless ? " is-horizontal-borderless" : ""}${hasStripedRows ? " is-striped" : ""}${insertBusy ? " is-inserting" : ""}${deleteBusy ? " is-deleting" : ""} ${loading && !hasCompletedLoadRef.current && !hasCustomLoading ? "is-initial-loading" : ""} ${className}`, style: rootStyle, children: [
|
|
4538
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `rvg-root${!hasVerticalBorders ? " is-vertical-borderless" : ""}${horizontalBorderless ? " is-horizontal-borderless" : ""}${frameBorderless ? " is-frame-borderless" : ""}${hasStripedRows ? " is-striped" : ""}${insertBusy ? " is-inserting" : ""}${deleteBusy ? " is-deleting" : ""} ${loading && !hasCompletedLoadRef.current && !hasCustomLoading ? "is-initial-loading" : ""} ${className}`, style: rootStyle, children: [
|
|
4496
4539
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { ref: scrollerRef, className: `rvg-scroller${contextMenu ? " is-context-menu-open" : ""}`, style: { bottom: scrollerBottom }, onScroll: handleScroll, onCopy: handleCopy, onContextMenu: handleContextMenu, tabIndex: 0, role: "grid", "aria-label": ariaLabel, "aria-rowcount": rows.length, "aria-colcount": columns.length, onKeyDown: handleKeyDown, children: [
|
|
4497
4540
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4498
4541
|
"canvas",
|
package/dist/index.css
CHANGED
|
@@ -757,6 +757,9 @@
|
|
|
757
757
|
background: var(--rvg-color-header-bg);
|
|
758
758
|
box-sizing: border-box;
|
|
759
759
|
}
|
|
760
|
+
.rvg-root.is-frame-borderless .rvg-header-group.is-frame-right {
|
|
761
|
+
border-right: 0;
|
|
762
|
+
}
|
|
760
763
|
.rvg-root.is-horizontal-borderless .rvg-header-group {
|
|
761
764
|
border-bottom: 0;
|
|
762
765
|
}
|
|
@@ -817,6 +820,9 @@
|
|
|
817
820
|
content: "";
|
|
818
821
|
pointer-events: none;
|
|
819
822
|
}
|
|
823
|
+
.rvg-root.is-frame-borderless .rvg-header-icons::after {
|
|
824
|
+
display: none;
|
|
825
|
+
}
|
|
820
826
|
.rvg-root.is-vertical-borderless .rvg-header-icons::after {
|
|
821
827
|
display: none;
|
|
822
828
|
}
|
|
@@ -836,8 +842,8 @@
|
|
|
836
842
|
}
|
|
837
843
|
.rvg-header-icon {
|
|
838
844
|
position: absolute;
|
|
839
|
-
width: 14px;
|
|
840
|
-
height: 14px;
|
|
845
|
+
width: var(--rvg-header-action-size, 14px);
|
|
846
|
+
height: var(--rvg-header-action-size, 14px);
|
|
841
847
|
overflow: visible;
|
|
842
848
|
color: var(--rvg-color-icon);
|
|
843
849
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -121,6 +121,8 @@ interface TableLayoutConfig {
|
|
|
121
121
|
rowHeight?: number;
|
|
122
122
|
/** Header height in pixels. Defaults to 40. */
|
|
123
123
|
headerHeight?: number;
|
|
124
|
+
/** Header action icon size in pixels. Defaults to 14. */
|
|
125
|
+
headerActionSize?: number;
|
|
124
126
|
}
|
|
125
127
|
interface TableCellSpan {
|
|
126
128
|
/** Row index in the current rows array. Prefer rowKey when row order can change. */
|
|
@@ -349,6 +351,8 @@ interface TableProps<Row extends object> {
|
|
|
349
351
|
verticalBorderless?: boolean;
|
|
350
352
|
/** Hide horizontal row and frame separators while keeping vertical grid lines. */
|
|
351
353
|
horizontalBorderless?: boolean;
|
|
354
|
+
/** Hide the outer table frame while keeping internal row and column separators. */
|
|
355
|
+
frameBorderless?: boolean;
|
|
352
356
|
/** Paint alternating row backgrounds. Pass a color string to customize the stripe color. */
|
|
353
357
|
striped?: boolean | string;
|
|
354
358
|
/** Visual highlight feedback configuration. All entries default to false. */
|
package/dist/index.d.ts
CHANGED
|
@@ -121,6 +121,8 @@ interface TableLayoutConfig {
|
|
|
121
121
|
rowHeight?: number;
|
|
122
122
|
/** Header height in pixels. Defaults to 40. */
|
|
123
123
|
headerHeight?: number;
|
|
124
|
+
/** Header action icon size in pixels. Defaults to 14. */
|
|
125
|
+
headerActionSize?: number;
|
|
124
126
|
}
|
|
125
127
|
interface TableCellSpan {
|
|
126
128
|
/** Row index in the current rows array. Prefer rowKey when row order can change. */
|
|
@@ -349,6 +351,8 @@ interface TableProps<Row extends object> {
|
|
|
349
351
|
verticalBorderless?: boolean;
|
|
350
352
|
/** Hide horizontal row and frame separators while keeping vertical grid lines. */
|
|
351
353
|
horizontalBorderless?: boolean;
|
|
354
|
+
/** Hide the outer table frame while keeping internal row and column separators. */
|
|
355
|
+
frameBorderless?: boolean;
|
|
352
356
|
/** Paint alternating row backgrounds. Pass a color string to customize the stripe color. */
|
|
353
357
|
striped?: boolean | string;
|
|
354
358
|
/** Visual highlight feedback configuration. All entries default to false. */
|
package/dist/index.js
CHANGED
|
@@ -792,8 +792,8 @@ function getHeaderTitleRequiredWidth(column, titleWidth) {
|
|
|
792
792
|
const minimumReadableTitleWidth = Math.min(Math.ceil(titleWidth), 28);
|
|
793
793
|
return minimumReadableTitleWidth + (column.align === "center" ? 20 : 22);
|
|
794
794
|
}
|
|
795
|
-
function getVisibleHeaderActions(column, width, columnDraggable = false, titleWidth = 26) {
|
|
796
|
-
const capacity = Math.max(0, Math.floor((width - getHeaderTitleRequiredWidth(column, titleWidth)) /
|
|
795
|
+
function getVisibleHeaderActions(column, width, columnDraggable = false, titleWidth = 26, actionSlotWidth = HEADER_ACTION_SLOT_WIDTH) {
|
|
796
|
+
const capacity = Math.max(0, Math.floor((width - getHeaderTitleRequiredWidth(column, titleWidth)) / actionSlotWidth));
|
|
797
797
|
const candidates = [
|
|
798
798
|
isColumnFilterable(column) ? "filter" : null,
|
|
799
799
|
isColumnSortable(column) ? "sort" : null,
|
|
@@ -912,7 +912,7 @@ function ellipsizeText(context, text, maxWidth) {
|
|
|
912
912
|
return `${text.slice(0, start)}${ellipsis}`;
|
|
913
913
|
}
|
|
914
914
|
function paintGrid(options) {
|
|
915
|
-
const { context: ctx, width, height, pixelRatio, scrollLeft, scrollTop, rowHeight, bodyFontSize, headerHeight, fixedHeader, verticalBorderless, horizontalBorderless, striped, columnDraggable, sortState, filterValues, hoveredHeaderAction, rows, columns, metrics, range, selection, editing, hoveredRowIndex, selectionRange, selectedRowKeys, rowSelectionMode, selectedColumnKeys, highlightEditedCells, highlightInsertedRows, insertedRowKeys, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview, columnDropTarget } = options;
|
|
915
|
+
const { context: ctx, width, height, pixelRatio, scrollLeft, scrollTop, rowHeight, bodyFontSize, headerActionSlotWidth, headerHeight, fixedHeader, verticalBorderless, horizontalBorderless, frameBorderless, extendVerticalGridLines, striped, columnDraggable, sortState, filterValues, hoveredHeaderAction, rows, columns, metrics, range, selection, editing, hoveredRowIndex, selectionRange, selectedRowKeys, rowSelectionMode, selectedColumnKeys, highlightEditedCells, highlightInsertedRows, insertedRowKeys, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview, columnDropTarget } = options;
|
|
916
916
|
const headerLeafTop = options.headerLeafTop ?? 0;
|
|
917
917
|
const headerLeafHeight = options.headerLeafHeight ?? headerHeight;
|
|
918
918
|
const colors = { ...COLORS, ...options.colors };
|
|
@@ -1033,7 +1033,9 @@ function paintGrid(options) {
|
|
|
1033
1033
|
ctx.fillRect(x, y, cellWidth, cellHeight);
|
|
1034
1034
|
}
|
|
1035
1035
|
ctx.fillStyle = colors.grid;
|
|
1036
|
-
if (!verticalBorderless
|
|
1036
|
+
if (!verticalBorderless && !(frameBorderless && columnIndex + colSpan >= columns.length)) {
|
|
1037
|
+
ctx.fillRect(x + cellWidth - 1, y, 1, cellHeight);
|
|
1038
|
+
}
|
|
1037
1039
|
if (rowIndex === rowBelowDragGap) ctx.fillRect(x, y, cellWidth, 1);
|
|
1038
1040
|
if (!horizontalBorderless && (!options.suppressLastRowBottomBorder || rowIndex !== rows.length - 1)) {
|
|
1039
1041
|
ctx.fillRect(x, y + cellHeight - 1, cellWidth, 1);
|
|
@@ -1152,6 +1154,30 @@ function paintGrid(options) {
|
|
|
1152
1154
|
paintBodyColumns("scroll");
|
|
1153
1155
|
paintBodyColumns("left");
|
|
1154
1156
|
paintBodyColumns("right");
|
|
1157
|
+
if (extendVerticalGridLines && !verticalBorderless) {
|
|
1158
|
+
const extensionTop = Math.max(bodyTop, Math.min(height, bodyTop + rows.length * rowHeight - scrollTop));
|
|
1159
|
+
const extensionHeight = Math.max(0, height - extensionTop);
|
|
1160
|
+
const paintExtendedColumnLines = (layer) => {
|
|
1161
|
+
ctx.save();
|
|
1162
|
+
if (layer === "scroll") {
|
|
1163
|
+
ctx.beginPath();
|
|
1164
|
+
ctx.rect(leftFixedWidth, extensionTop, Math.max(0, rightFixedLeft - leftFixedWidth), extensionHeight);
|
|
1165
|
+
ctx.clip();
|
|
1166
|
+
}
|
|
1167
|
+
ctx.fillStyle = colors.grid;
|
|
1168
|
+
for (let columnIndex = 0; columnIndex < columns.length; columnIndex += 1) {
|
|
1169
|
+
if (layer === "scroll" ? columns[columnIndex].fixed !== void 0 : columns[columnIndex].fixed !== layer) continue;
|
|
1170
|
+
if (layer === "scroll" && (columnIndex < range.columnStart || columnIndex >= range.columnEnd)) continue;
|
|
1171
|
+
if (frameBorderless && columnIndex === columns.length - 1) continue;
|
|
1172
|
+
const x = getColumnX(columnIndex) + metrics[columnIndex].width - 1;
|
|
1173
|
+
ctx.fillRect(x, extensionTop, 1, extensionHeight);
|
|
1174
|
+
}
|
|
1175
|
+
ctx.restore();
|
|
1176
|
+
};
|
|
1177
|
+
paintExtendedColumnLines("scroll");
|
|
1178
|
+
paintExtendedColumnLines("left");
|
|
1179
|
+
paintExtendedColumnLines("right");
|
|
1180
|
+
}
|
|
1155
1181
|
const headerY = fixedHeader ? 0 : -scrollTop;
|
|
1156
1182
|
ctx.fillStyle = colors.header;
|
|
1157
1183
|
ctx.fillRect(0, headerY, width, headerHeight);
|
|
@@ -1175,14 +1201,16 @@ function paintGrid(options) {
|
|
|
1175
1201
|
ctx.fillRect(x, headerY, metric.width, headerHeight);
|
|
1176
1202
|
}
|
|
1177
1203
|
ctx.fillStyle = colors.grid;
|
|
1178
|
-
if (!verticalBorderless
|
|
1204
|
+
if (!verticalBorderless && !(frameBorderless && columnIndex === columns.length - 1)) {
|
|
1205
|
+
ctx.fillRect(x + metric.width - 1, headerY, 1, headerHeight);
|
|
1206
|
+
}
|
|
1179
1207
|
if (!horizontalBorderless) ctx.fillRect(x, headerY + headerHeight - 1, metric.width, 1);
|
|
1180
1208
|
const column = columns[columnIndex];
|
|
1181
1209
|
if (headerLeafTop === 0 && !column.rowSelection && !column.rowDragHandle && !column.rowNumber && !column.renderHeader && column.title) {
|
|
1182
1210
|
ctx.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
1183
1211
|
const titleWidth = ctx.measureText(column.title).width;
|
|
1184
|
-
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth);
|
|
1185
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
1212
|
+
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth, headerActionSlotWidth);
|
|
1213
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth;
|
|
1186
1214
|
const contentWidth = Math.max(0, metric.width - actionWidth);
|
|
1187
1215
|
const padding = 10;
|
|
1188
1216
|
const clipWidth = contentWidth;
|
|
@@ -1212,12 +1240,12 @@ function paintGrid(options) {
|
|
|
1212
1240
|
ctx.fillRect(rightFixedLeft - 1, 0, 1, height);
|
|
1213
1241
|
}
|
|
1214
1242
|
ctx.fillStyle = colors.grid;
|
|
1215
|
-
if (!horizontalBorderless) ctx.fillRect(0, 0, width, 1);
|
|
1216
|
-
if (!verticalBorderless) {
|
|
1243
|
+
if (!horizontalBorderless && !frameBorderless) ctx.fillRect(0, 0, width, 1);
|
|
1244
|
+
if (!verticalBorderless && !frameBorderless) {
|
|
1217
1245
|
ctx.fillRect(0, 0, 1, height);
|
|
1218
1246
|
ctx.fillRect(width - 1, 0, 1, height);
|
|
1219
1247
|
}
|
|
1220
|
-
if (!horizontalBorderless && !options.suppressFrameBottomBorder) ctx.fillRect(0, height - 1, width, 1);
|
|
1248
|
+
if (!horizontalBorderless && !frameBorderless && !options.suppressFrameBottomBorder) ctx.fillRect(0, height - 1, width, 1);
|
|
1221
1249
|
if (selectionRange) {
|
|
1222
1250
|
const rowStart = Math.min(selectionRange.anchor.rowIndex, selectionRange.focus.rowIndex);
|
|
1223
1251
|
const rowEnd = Math.max(selectionRange.anchor.rowIndex, selectionRange.focus.rowIndex);
|
|
@@ -1526,6 +1554,7 @@ function TableInner({
|
|
|
1526
1554
|
borderless,
|
|
1527
1555
|
verticalBorderless,
|
|
1528
1556
|
horizontalBorderless = false,
|
|
1557
|
+
frameBorderless = false,
|
|
1529
1558
|
striped = false,
|
|
1530
1559
|
highlight,
|
|
1531
1560
|
cellSpans = [],
|
|
@@ -1572,6 +1601,8 @@ function TableInner({
|
|
|
1572
1601
|
setSourceColumns((current) => reconcileColumns(current, columnProps));
|
|
1573
1602
|
}, [columnProps]);
|
|
1574
1603
|
const rowHeight = layout?.rowHeight ?? rowHeightProp ?? 36;
|
|
1604
|
+
const headerActionSize = Math.max(8, layout?.headerActionSize ?? 14);
|
|
1605
|
+
const headerActionSlotWidth = headerActionSize + 2;
|
|
1575
1606
|
const baseHeaderHeight = layout?.headerHeight ?? headerHeightProp ?? 40;
|
|
1576
1607
|
const headerDepth = useMemo(() => Math.max(1, ...sourceColumns.map(getColumnDepth)), [sourceColumns]);
|
|
1577
1608
|
const { language, labels } = useMemo(() => resolveGridLocale(locale), [locale]);
|
|
@@ -2207,8 +2238,8 @@ function TableInner({
|
|
|
2207
2238
|
const scroll = scrollRef.current;
|
|
2208
2239
|
const rowScrollTop = fixedHeader ? scroll.top : Math.max(0, scroll.top - bodyTop);
|
|
2209
2240
|
const range = isVirtualized ? getViewportRange(scroll.left, rowScrollTop, viewport.width, bodyViewportHeight, rows.length, rowHeight, metrics, virtualOverscan) : { rowStart: 0, rowEnd: rows.length, columnStart: 0, columnEnd: columns.length };
|
|
2210
|
-
paintGrid({ context, width: viewport.width, height: renderHeight, pixelRatio: ratio, scrollLeft: scroll.left, scrollTop: scroll.top, rowHeight, bodyFontSize, headerHeight, headerLeafTop, headerLeafHeight, bodyTop, suppressLastRowBottomBorder: bottomSummaryHeight > 0, suppressFrameBottomBorder: bottomSummaryHeight > 0, fixedHeader, verticalBorderless: !hasVerticalBorders, horizontalBorderless, striped: hasStripedRows, columnDraggable, sortState, filterValues, hoveredHeaderAction: hoveredHeaderActionRef.current, rows, columns, metrics, range, selection, editing, hoveredRowIndex: hoveredRowIndexRef.current, selectionRange, selectedRowKeys: selectedRowKeySet, rowSelectionMode, selectedColumnKeys: selectedColumnKeySet, cellSpans: cellSpanLookup.covered, maxRowSpan: cellSpanLookup.maxRowSpan, highlightEditedCells: highlightsEditedCells, highlightInsertedRows: highlightsInsertedRows, insertedRowKeys: insertedRowKeySet, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview, columnDropTarget, colors: themeColors });
|
|
2211
|
-
}, [bodyTop, bodyViewportHeight, bottomSummaryHeight, cellAnnotations, cellSpanLookup, columnDraggable, columnDropTarget, columns, editedCellHighlightColor, editedCellKeys, editing, renderHeight, filterValues, fixedHeader, getRowKey, hasStripedRows, hasVerticalBorders, headerDepth, headerHeight, headerLeafHeight, headerLeafTop, horizontalBorderless, highlightsEditedCells, highlightsInsertedRows, insertedRowHighlightColor, insertedRowKeySet, isVirtualized, metrics, rowDragPreview, rowHeight, rowSelectionMode, rows, selectedColumnKeySet, selectedRowKeySet, selection, selectionRange, sortState, stripedColor, viewport.width, virtualOverscan]);
|
|
2241
|
+
paintGrid({ context, width: viewport.width, height: renderHeight, pixelRatio: ratio, scrollLeft: scroll.left, scrollTop: scroll.top, rowHeight, bodyFontSize, headerActionSlotWidth, headerHeight, headerLeafTop, headerLeafHeight, bodyTop, suppressLastRowBottomBorder: bottomSummaryHeight > 0, suppressFrameBottomBorder: bottomSummaryHeight > 0, fixedHeader, verticalBorderless: !hasVerticalBorders, horizontalBorderless, frameBorderless, extendVerticalGridLines: !autoHeight, striped: hasStripedRows, columnDraggable, sortState, filterValues, hoveredHeaderAction: hoveredHeaderActionRef.current, rows, columns, metrics, range, selection, editing, hoveredRowIndex: hoveredRowIndexRef.current, selectionRange, selectedRowKeys: selectedRowKeySet, rowSelectionMode, selectedColumnKeys: selectedColumnKeySet, cellSpans: cellSpanLookup.covered, maxRowSpan: cellSpanLookup.maxRowSpan, highlightEditedCells: highlightsEditedCells, highlightInsertedRows: highlightsInsertedRows, insertedRowKeys: insertedRowKeySet, editedCellKeys, cellAnnotations, getRowKey, rowDragPreview, columnDropTarget, colors: themeColors });
|
|
2242
|
+
}, [autoHeight, bodyTop, bodyViewportHeight, bottomSummaryHeight, cellAnnotations, cellSpanLookup, columnDraggable, columnDropTarget, columns, editedCellHighlightColor, editedCellKeys, editing, renderHeight, filterValues, fixedHeader, frameBorderless, getRowKey, hasStripedRows, hasVerticalBorders, headerActionSlotWidth, headerDepth, headerHeight, headerLeafHeight, headerLeafTop, horizontalBorderless, highlightsEditedCells, highlightsInsertedRows, insertedRowHighlightColor, insertedRowKeySet, isVirtualized, metrics, rowDragPreview, rowHeight, rowSelectionMode, rows, selectedColumnKeySet, selectedRowKeySet, selection, selectionRange, sortState, stripedColor, viewport.width, virtualOverscan]);
|
|
2212
2243
|
const scheduleDraw = useCallback2(() => {
|
|
2213
2244
|
if (frameRef.current === null) frameRef.current = requestAnimationFrame(draw);
|
|
2214
2245
|
}, [draw]);
|
|
@@ -2774,34 +2805,34 @@ function TableInner({
|
|
|
2774
2805
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
|
|
2775
2806
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2776
2807
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2777
|
-
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
2778
|
-
let right = columnRight - (visibleActions.drag ?
|
|
2808
|
+
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
2809
|
+
let right = columnRight - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
2779
2810
|
if (visibleActions.sort) {
|
|
2780
|
-
if (localX >= right -
|
|
2781
|
-
right -=
|
|
2811
|
+
if (localX >= right - headerActionSlotWidth && localX < right) return "sort";
|
|
2812
|
+
right -= headerActionSlotWidth;
|
|
2782
2813
|
}
|
|
2783
|
-
if (visibleActions.filter && localX >= right -
|
|
2814
|
+
if (visibleActions.filter && localX >= right - headerActionSlotWidth && localX < right) return "filter";
|
|
2784
2815
|
return null;
|
|
2785
|
-
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2816
|
+
}, [columnDraggable, columns, getDisplayedColumnLeft, headerActionSlotWidth, measureHeaderTitleWidth, metrics]);
|
|
2786
2817
|
const isHeaderTitleTruncated = useCallback2((columnIndex) => {
|
|
2787
2818
|
const canvas = canvasRef.current;
|
|
2788
2819
|
if (columnIndex < 0 || !canvas) return false;
|
|
2789
2820
|
const column = columns[columnIndex];
|
|
2790
2821
|
const metric = metrics[columnIndex];
|
|
2791
2822
|
const titleWidth = measureHeaderTitleWidth(columnIndex);
|
|
2792
|
-
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth);
|
|
2793
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
2823
|
+
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth, headerActionSlotWidth);
|
|
2824
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth;
|
|
2794
2825
|
return getHeaderTitleRequiredWidth(column, titleWidth) > Math.max(0, metric.width - actionWidth);
|
|
2795
|
-
}, [columnDraggable, columns, measureHeaderTitleWidth, metrics]);
|
|
2826
|
+
}, [columnDraggable, columns, headerActionSlotWidth, measureHeaderTitleWidth, metrics]);
|
|
2796
2827
|
const locateHeaderDragHandle = useCallback2((clientX, columnIndex) => {
|
|
2797
2828
|
if (!columnDraggable || columnIndex < 0 || !canvasRef.current) return false;
|
|
2798
2829
|
const column = columns[columnIndex];
|
|
2799
2830
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return false;
|
|
2800
|
-
if (!getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex)).drag) return false;
|
|
2831
|
+
if (!getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth).drag) return false;
|
|
2801
2832
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2802
2833
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2803
|
-
return localX >= columnRight -
|
|
2804
|
-
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2834
|
+
return localX >= columnRight - headerActionSlotWidth && localX < columnRight - 2;
|
|
2835
|
+
}, [columnDraggable, columns, getDisplayedColumnLeft, headerActionSlotWidth, measureHeaderTitleWidth, metrics]);
|
|
2805
2836
|
const getHeaderCellLeft = useCallback2((cell) => {
|
|
2806
2837
|
const startMetric = metrics[cell.startIndex];
|
|
2807
2838
|
const fixedSide = columns[cell.startIndex]?.fixed;
|
|
@@ -2866,8 +2897,8 @@ function TableInner({
|
|
|
2866
2897
|
if (cell.leaf) return locateHeaderDragHandle(clientX, cell.startIndex);
|
|
2867
2898
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2868
2899
|
const right = getHeaderCellLeft(cell) + getHeaderCellWidth(cell);
|
|
2869
|
-
return localX >= right -
|
|
2870
|
-
}, [columnDraggable, getHeaderCellLeft, getHeaderCellWidth, locateHeaderDragHandle]);
|
|
2900
|
+
return localX >= right - headerActionSlotWidth && localX < right - 2;
|
|
2901
|
+
}, [columnDraggable, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, locateHeaderDragHandle]);
|
|
2871
2902
|
const locateHeaderCell = useCallback2((clientX, clientY) => {
|
|
2872
2903
|
const canvas = canvasRef.current;
|
|
2873
2904
|
if (!canvas) return null;
|
|
@@ -3023,26 +3054,32 @@ function TableInner({
|
|
|
3023
3054
|
header.style.height = `${headerHeight}px`;
|
|
3024
3055
|
header.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
|
|
3025
3056
|
header.textContent = column.title;
|
|
3026
|
-
const visibleActions = getVisibleHeaderActions(column, columnWidth, columnDraggable, measureHeaderTitleWidth(sourceIndex));
|
|
3057
|
+
const visibleActions = getVisibleHeaderActions(column, columnWidth, columnDraggable, measureHeaderTitleWidth(sourceIndex), headerActionSlotWidth);
|
|
3027
3058
|
let actionRight = 2;
|
|
3028
3059
|
if (visibleActions.drag) {
|
|
3029
3060
|
const icon = createHeaderDragHandleSvg();
|
|
3030
3061
|
icon.classList.add("rvg-preview-header-icon");
|
|
3062
|
+
icon.style.width = `${headerActionSize}px`;
|
|
3063
|
+
icon.style.height = `${headerActionSize}px`;
|
|
3031
3064
|
icon.style.right = `${actionRight}px`;
|
|
3032
3065
|
header.appendChild(icon);
|
|
3033
|
-
actionRight +=
|
|
3066
|
+
actionRight += headerActionSlotWidth;
|
|
3034
3067
|
}
|
|
3035
3068
|
if (visibleActions.sort) {
|
|
3036
3069
|
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3037
3070
|
const icon = createHeaderSortSvg(direction);
|
|
3038
3071
|
icon.classList.add("rvg-preview-header-icon");
|
|
3072
|
+
icon.style.width = `${headerActionSize}px`;
|
|
3073
|
+
icon.style.height = `${headerActionSize}px`;
|
|
3039
3074
|
icon.style.right = `${actionRight}px`;
|
|
3040
3075
|
header.appendChild(icon);
|
|
3041
|
-
actionRight +=
|
|
3076
|
+
actionRight += headerActionSlotWidth;
|
|
3042
3077
|
}
|
|
3043
3078
|
if (visibleActions.filter) {
|
|
3044
3079
|
const icon = createHeaderSearchSvg(Boolean(filterValues[column.key]));
|
|
3045
3080
|
icon.classList.add("rvg-preview-header-icon", "rvg-preview-header-search-icon");
|
|
3081
|
+
icon.style.width = `${headerActionSize}px`;
|
|
3082
|
+
icon.style.height = `${headerActionSize}px`;
|
|
3046
3083
|
icon.style.right = `${actionRight}px`;
|
|
3047
3084
|
header.appendChild(icon);
|
|
3048
3085
|
}
|
|
@@ -3239,7 +3276,7 @@ function TableInner({
|
|
|
3239
3276
|
cleanupDrag();
|
|
3240
3277
|
cleanupDrop();
|
|
3241
3278
|
};
|
|
3242
|
-
}, [applyColumnOrder, applyRowOrder, bodyTop, columnDraggable, columns, filterValues, fixedHeader, getCellLabel, getDisplayedColumnLeft, getHeaderCellWidth, getRowKey, headerCells, headerHeight, hideDragTooltips, locateColumn, locateHeaderCell, locateHeaderCellDragHandle, locateHeaderResizeCell, locateRow, measureHeaderTitleWidth, metrics, rowDraggable, rowHeight, rows, selectedRowKeySet, selection, setDragGuide, setRowDragGuide, sortState, utilityColumnCount]);
|
|
3279
|
+
}, [applyColumnOrder, applyRowOrder, bodyTop, columnDraggable, columns, filterValues, fixedHeader, getCellLabel, getDisplayedColumnLeft, getHeaderCellWidth, getRowKey, headerActionSize, headerActionSlotWidth, headerCells, headerHeight, hideDragTooltips, locateColumn, locateHeaderCell, locateHeaderCellDragHandle, locateHeaderResizeCell, locateRow, measureHeaderTitleWidth, metrics, rowDraggable, rowHeight, rows, selectedRowKeySet, selection, setDragGuide, setRowDragGuide, sortState, utilityColumnCount]);
|
|
3243
3280
|
const locateCell = useCallback2((clientX, clientY) => {
|
|
3244
3281
|
const canvas = canvasRef.current;
|
|
3245
3282
|
if (!canvas) return null;
|
|
@@ -3683,28 +3720,28 @@ function TableInner({
|
|
|
3683
3720
|
const renderHeaderIcons = (columnIndex, left) => {
|
|
3684
3721
|
const column = columns[columnIndex];
|
|
3685
3722
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
|
|
3686
|
-
const top = headerLeafTop + (headerLeafHeight -
|
|
3687
|
-
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
3688
|
-
let right = left + metrics[columnIndex].width - (visibleActions.drag ?
|
|
3723
|
+
const top = headerLeafTop + (headerLeafHeight - headerActionSize) / 2;
|
|
3724
|
+
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
3725
|
+
let right = left + metrics[columnIndex].width - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
3689
3726
|
const icons = [];
|
|
3690
3727
|
if (visibleActions.drag) {
|
|
3691
3728
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "drag";
|
|
3692
3729
|
icons.push(
|
|
3693
|
-
/* @__PURE__ */ jsx7(HeaderDragIcon, { className: `rvg-header-icon rvg-header-drag-icon${hovered ? " is-hovered" : ""}`, style: { left: left + metrics[columnIndex].width -
|
|
3730
|
+
/* @__PURE__ */ jsx7(HeaderDragIcon, { className: `rvg-header-icon rvg-header-drag-icon${hovered ? " is-hovered" : ""}`, style: { left: left + metrics[columnIndex].width - headerActionSlotWidth, top } }, "drag")
|
|
3694
3731
|
);
|
|
3695
3732
|
}
|
|
3696
3733
|
if (visibleActions.sort) {
|
|
3697
3734
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "sort";
|
|
3698
3735
|
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3699
3736
|
icons.push(
|
|
3700
|
-
/* @__PURE__ */ jsx7(HeaderSortIcon, { className: `rvg-header-icon${hovered ? " is-hovered" : ""}`, style: { left: right -
|
|
3737
|
+
/* @__PURE__ */ jsx7(HeaderSortIcon, { className: `rvg-header-icon${hovered ? " is-hovered" : ""}`, style: { left: right - headerActionSlotWidth, top }, direction }, "sort")
|
|
3701
3738
|
);
|
|
3702
|
-
right -=
|
|
3739
|
+
right -= headerActionSlotWidth;
|
|
3703
3740
|
}
|
|
3704
3741
|
if (visibleActions.filter) {
|
|
3705
3742
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "filter";
|
|
3706
3743
|
icons.push(
|
|
3707
|
-
/* @__PURE__ */ jsx7(HeaderSearchIcon, { className: `rvg-header-icon rvg-header-search-icon${hovered ? " is-hovered" : ""}${filterValues[column.key] ? " is-active" : ""}`, style: { left: right -
|
|
3744
|
+
/* @__PURE__ */ jsx7(HeaderSearchIcon, { className: `rvg-header-icon rvg-header-search-icon${hovered ? " is-hovered" : ""}${filterValues[column.key] ? " is-active" : ""}`, style: { left: right - headerActionSlotWidth, top: top + 1 } }, "filter")
|
|
3708
3745
|
);
|
|
3709
3746
|
}
|
|
3710
3747
|
return icons;
|
|
@@ -3725,8 +3762,8 @@ function TableInner({
|
|
|
3725
3762
|
const context = canvas?.getContext("2d");
|
|
3726
3763
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3727
3764
|
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3728
|
-
const visibleActions = cell?.leaf || !cell ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3729
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
3765
|
+
const visibleActions = cell?.leaf || !cell ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth, headerActionSlotWidth) : null;
|
|
3766
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth : columnDraggable ? headerActionSlotWidth : 0;
|
|
3730
3767
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3731
3768
|
const maxTextWidth = Math.max(0, contentWidth2 - 20);
|
|
3732
3769
|
const textWidth = Math.min(titleWidth, maxTextWidth);
|
|
@@ -3747,12 +3784,17 @@ function TableInner({
|
|
|
3747
3784
|
} else if (action === "sort") {
|
|
3748
3785
|
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3749
3786
|
label = direction === "asc" ? labels.sortAsc : direction === "desc" ? labels.sortDesc : labels.sortBoth;
|
|
3750
|
-
|
|
3787
|
+
const visibleActions = getVisibleHeaderActions(column, cellWidth, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
3788
|
+
const right = cellLeft + cellWidth - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
3789
|
+
anchorX = right - headerActionSlotWidth / 2;
|
|
3751
3790
|
anchorLeft = anchorX;
|
|
3752
3791
|
} else if (action === "filter") {
|
|
3753
3792
|
const value = filterValues[column.key];
|
|
3754
3793
|
label = value ? labels.filterWithValue(value) : labels.filter;
|
|
3755
|
-
|
|
3794
|
+
const visibleActions = getVisibleHeaderActions(column, cellWidth, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
3795
|
+
let right = cellLeft + cellWidth - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
3796
|
+
if (visibleActions.sort) right -= headerActionSlotWidth;
|
|
3797
|
+
anchorX = right - headerActionSlotWidth / 2;
|
|
3756
3798
|
anchorLeft = anchorX;
|
|
3757
3799
|
}
|
|
3758
3800
|
const placement = anchorX + 328 > viewport.width ? "left" : "right";
|
|
@@ -3765,7 +3807,7 @@ function TableInner({
|
|
|
3765
3807
|
label,
|
|
3766
3808
|
placement
|
|
3767
3809
|
};
|
|
3768
|
-
}, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, metrics, scrollPosition.top, sortState, viewport.width]);
|
|
3810
|
+
}, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, measureHeaderTitleWidth, metrics, scrollPosition.top, sortState, viewport.width]);
|
|
3769
3811
|
const isPointerOnHeaderTitle = useCallback2((clientX, clientY, cell) => {
|
|
3770
3812
|
const canvas = canvasRef.current;
|
|
3771
3813
|
if (!canvas) return false;
|
|
@@ -3779,14 +3821,14 @@ function TableInner({
|
|
|
3779
3821
|
const context = canvas.getContext("2d");
|
|
3780
3822
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3781
3823
|
const titleWidth = context?.measureText(column.title).width ?? column.title.length * 13;
|
|
3782
|
-
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth) : null;
|
|
3783
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
3824
|
+
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth, headerActionSlotWidth) : null;
|
|
3825
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth : columnDraggable ? headerActionSlotWidth : 0;
|
|
3784
3826
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3785
3827
|
const textWidth = Math.min(titleWidth, Math.max(0, contentWidth2 - 20));
|
|
3786
3828
|
const textLeft = column.align === "right" ? cellLeft + contentWidth2 - 10 - textWidth : column.align === "center" ? cellLeft + contentWidth2 / 2 - textWidth / 2 : cellLeft + 10;
|
|
3787
3829
|
const textTop = rowTop + 8;
|
|
3788
3830
|
return localX >= textLeft - 4 && localX <= textLeft + textWidth + 4 && localY >= textTop - 2 && localY <= textTop + 18;
|
|
3789
|
-
}, [columnDraggable, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerRowOffsets]);
|
|
3831
|
+
}, [columnDraggable, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, headerRowOffsets]);
|
|
3790
3832
|
const headerTooltip = (() => {
|
|
3791
3833
|
if (!visibleHeaderTooltip) return null;
|
|
3792
3834
|
return visibleHeaderTooltip;
|
|
@@ -4109,8 +4151,8 @@ function TableInner({
|
|
|
4109
4151
|
);
|
|
4110
4152
|
}
|
|
4111
4153
|
if (column.renderHeader) {
|
|
4112
|
-
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
4113
|
-
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
4154
|
+
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
4155
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth;
|
|
4114
4156
|
return /* @__PURE__ */ jsx7(
|
|
4115
4157
|
"div",
|
|
4116
4158
|
{
|
|
@@ -4154,13 +4196,13 @@ function TableInner({
|
|
|
4154
4196
|
const headerTop = (fixedHeader ? 0 : -currentScrollTop) + (headerRowOffsets[cell.level] ?? 0);
|
|
4155
4197
|
const left = fixedSide === "left" ? leftFixedOffsets.get(cell.startIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(cell.startIndex) ?? 0) - startMetric.width : getScrollableColumnLeft(cell.startIndex);
|
|
4156
4198
|
const width2 = cell.leaf ? startMetric.width : getCellDisplayWidth(cell.startIndex, cell.endIndex - cell.startIndex + 1);
|
|
4157
|
-
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, startMetric.width, columnDraggable, measureHeaderTitleWidth(cell.startIndex)) : null;
|
|
4158
|
-
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) *
|
|
4199
|
+
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, startMetric.width, columnDraggable, measureHeaderTitleWidth(cell.startIndex), headerActionSlotWidth) : null;
|
|
4200
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth : columnDraggable && !cell.leaf ? headerActionSlotWidth : 0;
|
|
4159
4201
|
const isDropTarget = Boolean(columnDropTarget && cell.endIndex >= columnDropTarget.startIndex && cell.startIndex <= columnDropTarget.endIndex);
|
|
4160
4202
|
return /* @__PURE__ */ jsxs7(
|
|
4161
4203
|
"div",
|
|
4162
4204
|
{
|
|
4163
|
-
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}${isDropTarget ? " is-drop-target" : ""}`,
|
|
4205
|
+
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}${cell.endIndex === columns.length - 1 ? " is-frame-right" : ""}${isDropTarget ? " is-drop-target" : ""}`,
|
|
4164
4206
|
"data-level": cell.level,
|
|
4165
4207
|
"data-measure-key": `group:${cell.key}:${cell.level}`,
|
|
4166
4208
|
style: {
|
|
@@ -4191,7 +4233,7 @@ function TableInner({
|
|
|
4191
4233
|
HeaderDragIcon,
|
|
4192
4234
|
{
|
|
4193
4235
|
className: `rvg-header-icon rvg-header-drag-icon${hoveredHeaderAction?.columnIndex === cell.startIndex && hoveredHeaderAction.action === "drag" ? " is-hovered" : ""}`,
|
|
4194
|
-
style: { left: width2 -
|
|
4236
|
+
style: { left: width2 - headerActionSlotWidth, top: (rowHeightForLevel - headerActionSize) / 2 }
|
|
4195
4237
|
}
|
|
4196
4238
|
)
|
|
4197
4239
|
]
|
|
@@ -4457,12 +4499,13 @@ function TableInner({
|
|
|
4457
4499
|
width,
|
|
4458
4500
|
height: autoHeight ? effectiveHeight : height,
|
|
4459
4501
|
minHeight: autoHeight || typeof height === "number" ? void 0 : FALLBACK_HEIGHT,
|
|
4502
|
+
"--rvg-header-action-size": `${headerActionSize}px`,
|
|
4460
4503
|
...stripedColor ? { "--rvg-color-stripe": stripedColor } : null,
|
|
4461
4504
|
...style
|
|
4462
4505
|
};
|
|
4463
4506
|
const currentScroll = scrollRef.current;
|
|
4464
4507
|
const scrollerBottom = Math.max(0, bottomSummaryHeight - horizontalScrollbarHeight);
|
|
4465
|
-
return /* @__PURE__ */ jsxs7("div", { className: `rvg-root${!hasVerticalBorders ? " is-vertical-borderless" : ""}${horizontalBorderless ? " is-horizontal-borderless" : ""}${hasStripedRows ? " is-striped" : ""}${insertBusy ? " is-inserting" : ""}${deleteBusy ? " is-deleting" : ""} ${loading && !hasCompletedLoadRef.current && !hasCustomLoading ? "is-initial-loading" : ""} ${className}`, style: rootStyle, children: [
|
|
4508
|
+
return /* @__PURE__ */ jsxs7("div", { className: `rvg-root${!hasVerticalBorders ? " is-vertical-borderless" : ""}${horizontalBorderless ? " is-horizontal-borderless" : ""}${frameBorderless ? " is-frame-borderless" : ""}${hasStripedRows ? " is-striped" : ""}${insertBusy ? " is-inserting" : ""}${deleteBusy ? " is-deleting" : ""} ${loading && !hasCompletedLoadRef.current && !hasCustomLoading ? "is-initial-loading" : ""} ${className}`, style: rootStyle, children: [
|
|
4466
4509
|
/* @__PURE__ */ jsxs7("div", { ref: scrollerRef, className: `rvg-scroller${contextMenu ? " is-context-menu-open" : ""}`, style: { bottom: scrollerBottom }, onScroll: handleScroll, onCopy: handleCopy, onContextMenu: handleContextMenu, tabIndex: 0, role: "grid", "aria-label": ariaLabel, "aria-rowcount": rows.length, "aria-colcount": columns.length, onKeyDown: handleKeyDown, children: [
|
|
4467
4510
|
/* @__PURE__ */ jsx7(
|
|
4468
4511
|
"canvas",
|