@lensui/lens-table 0.1.11 → 0.1.12
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 +71 -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 +71 -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, 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);
|
|
@@ -1205,14 +1207,16 @@ function paintGrid(options) {
|
|
|
1205
1207
|
ctx.fillRect(x, headerY, metric.width, headerHeight);
|
|
1206
1208
|
}
|
|
1207
1209
|
ctx.fillStyle = colors.grid;
|
|
1208
|
-
if (!verticalBorderless
|
|
1210
|
+
if (!verticalBorderless && !(frameBorderless && columnIndex === columns.length - 1)) {
|
|
1211
|
+
ctx.fillRect(x + metric.width - 1, headerY, 1, headerHeight);
|
|
1212
|
+
}
|
|
1209
1213
|
if (!horizontalBorderless) ctx.fillRect(x, headerY + headerHeight - 1, metric.width, 1);
|
|
1210
1214
|
const column = columns[columnIndex];
|
|
1211
1215
|
if (headerLeafTop === 0 && !column.rowSelection && !column.rowDragHandle && !column.rowNumber && !column.renderHeader && column.title) {
|
|
1212
1216
|
ctx.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
1213
1217
|
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)) *
|
|
1218
|
+
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth, headerActionSlotWidth);
|
|
1219
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth;
|
|
1216
1220
|
const contentWidth = Math.max(0, metric.width - actionWidth);
|
|
1217
1221
|
const padding = 10;
|
|
1218
1222
|
const clipWidth = contentWidth;
|
|
@@ -1242,12 +1246,12 @@ function paintGrid(options) {
|
|
|
1242
1246
|
ctx.fillRect(rightFixedLeft - 1, 0, 1, height);
|
|
1243
1247
|
}
|
|
1244
1248
|
ctx.fillStyle = colors.grid;
|
|
1245
|
-
if (!horizontalBorderless) ctx.fillRect(0, 0, width, 1);
|
|
1246
|
-
if (!verticalBorderless) {
|
|
1249
|
+
if (!horizontalBorderless && !frameBorderless) ctx.fillRect(0, 0, width, 1);
|
|
1250
|
+
if (!verticalBorderless && !frameBorderless) {
|
|
1247
1251
|
ctx.fillRect(0, 0, 1, height);
|
|
1248
1252
|
ctx.fillRect(width - 1, 0, 1, height);
|
|
1249
1253
|
}
|
|
1250
|
-
if (!horizontalBorderless && !options.suppressFrameBottomBorder) ctx.fillRect(0, height - 1, width, 1);
|
|
1254
|
+
if (!horizontalBorderless && !frameBorderless && !options.suppressFrameBottomBorder) ctx.fillRect(0, height - 1, width, 1);
|
|
1251
1255
|
if (selectionRange) {
|
|
1252
1256
|
const rowStart = Math.min(selectionRange.anchor.rowIndex, selectionRange.focus.rowIndex);
|
|
1253
1257
|
const rowEnd = Math.max(selectionRange.anchor.rowIndex, selectionRange.focus.rowIndex);
|
|
@@ -1556,6 +1560,7 @@ function TableInner({
|
|
|
1556
1560
|
borderless,
|
|
1557
1561
|
verticalBorderless,
|
|
1558
1562
|
horizontalBorderless = false,
|
|
1563
|
+
frameBorderless = false,
|
|
1559
1564
|
striped = false,
|
|
1560
1565
|
highlight,
|
|
1561
1566
|
cellSpans = [],
|
|
@@ -1602,6 +1607,8 @@ function TableInner({
|
|
|
1602
1607
|
setSourceColumns((current) => reconcileColumns(current, columnProps));
|
|
1603
1608
|
}, [columnProps]);
|
|
1604
1609
|
const rowHeight = layout?.rowHeight ?? rowHeightProp ?? 36;
|
|
1610
|
+
const headerActionSize = Math.max(8, layout?.headerActionSize ?? 14);
|
|
1611
|
+
const headerActionSlotWidth = headerActionSize + 2;
|
|
1605
1612
|
const baseHeaderHeight = layout?.headerHeight ?? headerHeightProp ?? 40;
|
|
1606
1613
|
const headerDepth = (0, import_react5.useMemo)(() => Math.max(1, ...sourceColumns.map(getColumnDepth)), [sourceColumns]);
|
|
1607
1614
|
const { language, labels } = (0, import_react5.useMemo)(() => resolveGridLocale(locale), [locale]);
|
|
@@ -2237,8 +2244,8 @@ function TableInner({
|
|
|
2237
2244
|
const scroll = scrollRef.current;
|
|
2238
2245
|
const rowScrollTop = fixedHeader ? scroll.top : Math.max(0, scroll.top - bodyTop);
|
|
2239
2246
|
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]);
|
|
2247
|
+
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, 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 });
|
|
2248
|
+
}, [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
2249
|
const scheduleDraw = (0, import_react5.useCallback)(() => {
|
|
2243
2250
|
if (frameRef.current === null) frameRef.current = requestAnimationFrame(draw);
|
|
2244
2251
|
}, [draw]);
|
|
@@ -2804,34 +2811,34 @@ function TableInner({
|
|
|
2804
2811
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
|
|
2805
2812
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2806
2813
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2807
|
-
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
2808
|
-
let right = columnRight - (visibleActions.drag ?
|
|
2814
|
+
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
2815
|
+
let right = columnRight - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
2809
2816
|
if (visibleActions.sort) {
|
|
2810
|
-
if (localX >= right -
|
|
2811
|
-
right -=
|
|
2817
|
+
if (localX >= right - headerActionSlotWidth && localX < right) return "sort";
|
|
2818
|
+
right -= headerActionSlotWidth;
|
|
2812
2819
|
}
|
|
2813
|
-
if (visibleActions.filter && localX >= right -
|
|
2820
|
+
if (visibleActions.filter && localX >= right - headerActionSlotWidth && localX < right) return "filter";
|
|
2814
2821
|
return null;
|
|
2815
|
-
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2822
|
+
}, [columnDraggable, columns, getDisplayedColumnLeft, headerActionSlotWidth, measureHeaderTitleWidth, metrics]);
|
|
2816
2823
|
const isHeaderTitleTruncated = (0, import_react5.useCallback)((columnIndex) => {
|
|
2817
2824
|
const canvas = canvasRef.current;
|
|
2818
2825
|
if (columnIndex < 0 || !canvas) return false;
|
|
2819
2826
|
const column = columns[columnIndex];
|
|
2820
2827
|
const metric = metrics[columnIndex];
|
|
2821
2828
|
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)) *
|
|
2829
|
+
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth, headerActionSlotWidth);
|
|
2830
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth;
|
|
2824
2831
|
return getHeaderTitleRequiredWidth(column, titleWidth) > Math.max(0, metric.width - actionWidth);
|
|
2825
|
-
}, [columnDraggable, columns, measureHeaderTitleWidth, metrics]);
|
|
2832
|
+
}, [columnDraggable, columns, headerActionSlotWidth, measureHeaderTitleWidth, metrics]);
|
|
2826
2833
|
const locateHeaderDragHandle = (0, import_react5.useCallback)((clientX, columnIndex) => {
|
|
2827
2834
|
if (!columnDraggable || columnIndex < 0 || !canvasRef.current) return false;
|
|
2828
2835
|
const column = columns[columnIndex];
|
|
2829
2836
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return false;
|
|
2830
|
-
if (!getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex)).drag) return false;
|
|
2837
|
+
if (!getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth).drag) return false;
|
|
2831
2838
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2832
2839
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2833
|
-
return localX >= columnRight -
|
|
2834
|
-
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2840
|
+
return localX >= columnRight - headerActionSlotWidth && localX < columnRight - 2;
|
|
2841
|
+
}, [columnDraggable, columns, getDisplayedColumnLeft, headerActionSlotWidth, measureHeaderTitleWidth, metrics]);
|
|
2835
2842
|
const getHeaderCellLeft = (0, import_react5.useCallback)((cell) => {
|
|
2836
2843
|
const startMetric = metrics[cell.startIndex];
|
|
2837
2844
|
const fixedSide = columns[cell.startIndex]?.fixed;
|
|
@@ -2896,8 +2903,8 @@ function TableInner({
|
|
|
2896
2903
|
if (cell.leaf) return locateHeaderDragHandle(clientX, cell.startIndex);
|
|
2897
2904
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2898
2905
|
const right = getHeaderCellLeft(cell) + getHeaderCellWidth(cell);
|
|
2899
|
-
return localX >= right -
|
|
2900
|
-
}, [columnDraggable, getHeaderCellLeft, getHeaderCellWidth, locateHeaderDragHandle]);
|
|
2906
|
+
return localX >= right - headerActionSlotWidth && localX < right - 2;
|
|
2907
|
+
}, [columnDraggable, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, locateHeaderDragHandle]);
|
|
2901
2908
|
const locateHeaderCell = (0, import_react5.useCallback)((clientX, clientY) => {
|
|
2902
2909
|
const canvas = canvasRef.current;
|
|
2903
2910
|
if (!canvas) return null;
|
|
@@ -3053,26 +3060,32 @@ function TableInner({
|
|
|
3053
3060
|
header.style.height = `${headerHeight}px`;
|
|
3054
3061
|
header.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
|
|
3055
3062
|
header.textContent = column.title;
|
|
3056
|
-
const visibleActions = getVisibleHeaderActions(column, columnWidth, columnDraggable, measureHeaderTitleWidth(sourceIndex));
|
|
3063
|
+
const visibleActions = getVisibleHeaderActions(column, columnWidth, columnDraggable, measureHeaderTitleWidth(sourceIndex), headerActionSlotWidth);
|
|
3057
3064
|
let actionRight = 2;
|
|
3058
3065
|
if (visibleActions.drag) {
|
|
3059
3066
|
const icon = createHeaderDragHandleSvg();
|
|
3060
3067
|
icon.classList.add("rvg-preview-header-icon");
|
|
3068
|
+
icon.style.width = `${headerActionSize}px`;
|
|
3069
|
+
icon.style.height = `${headerActionSize}px`;
|
|
3061
3070
|
icon.style.right = `${actionRight}px`;
|
|
3062
3071
|
header.appendChild(icon);
|
|
3063
|
-
actionRight +=
|
|
3072
|
+
actionRight += headerActionSlotWidth;
|
|
3064
3073
|
}
|
|
3065
3074
|
if (visibleActions.sort) {
|
|
3066
3075
|
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3067
3076
|
const icon = createHeaderSortSvg(direction);
|
|
3068
3077
|
icon.classList.add("rvg-preview-header-icon");
|
|
3078
|
+
icon.style.width = `${headerActionSize}px`;
|
|
3079
|
+
icon.style.height = `${headerActionSize}px`;
|
|
3069
3080
|
icon.style.right = `${actionRight}px`;
|
|
3070
3081
|
header.appendChild(icon);
|
|
3071
|
-
actionRight +=
|
|
3082
|
+
actionRight += headerActionSlotWidth;
|
|
3072
3083
|
}
|
|
3073
3084
|
if (visibleActions.filter) {
|
|
3074
3085
|
const icon = createHeaderSearchSvg(Boolean(filterValues[column.key]));
|
|
3075
3086
|
icon.classList.add("rvg-preview-header-icon", "rvg-preview-header-search-icon");
|
|
3087
|
+
icon.style.width = `${headerActionSize}px`;
|
|
3088
|
+
icon.style.height = `${headerActionSize}px`;
|
|
3076
3089
|
icon.style.right = `${actionRight}px`;
|
|
3077
3090
|
header.appendChild(icon);
|
|
3078
3091
|
}
|
|
@@ -3269,7 +3282,7 @@ function TableInner({
|
|
|
3269
3282
|
cleanupDrag();
|
|
3270
3283
|
cleanupDrop();
|
|
3271
3284
|
};
|
|
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]);
|
|
3285
|
+
}, [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
3286
|
const locateCell = (0, import_react5.useCallback)((clientX, clientY) => {
|
|
3274
3287
|
const canvas = canvasRef.current;
|
|
3275
3288
|
if (!canvas) return null;
|
|
@@ -3713,28 +3726,28 @@ function TableInner({
|
|
|
3713
3726
|
const renderHeaderIcons = (columnIndex, left) => {
|
|
3714
3727
|
const column = columns[columnIndex];
|
|
3715
3728
|
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 ?
|
|
3729
|
+
const top = headerLeafTop + (headerLeafHeight - headerActionSize) / 2;
|
|
3730
|
+
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
3731
|
+
let right = left + metrics[columnIndex].width - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
3719
3732
|
const icons = [];
|
|
3720
3733
|
if (visibleActions.drag) {
|
|
3721
3734
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "drag";
|
|
3722
3735
|
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 -
|
|
3736
|
+
/* @__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
3737
|
);
|
|
3725
3738
|
}
|
|
3726
3739
|
if (visibleActions.sort) {
|
|
3727
3740
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "sort";
|
|
3728
3741
|
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3729
3742
|
icons.push(
|
|
3730
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HeaderSortIcon, { className: `rvg-header-icon${hovered ? " is-hovered" : ""}`, style: { left: right -
|
|
3743
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(HeaderSortIcon, { className: `rvg-header-icon${hovered ? " is-hovered" : ""}`, style: { left: right - headerActionSlotWidth, top }, direction }, "sort")
|
|
3731
3744
|
);
|
|
3732
|
-
right -=
|
|
3745
|
+
right -= headerActionSlotWidth;
|
|
3733
3746
|
}
|
|
3734
3747
|
if (visibleActions.filter) {
|
|
3735
3748
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "filter";
|
|
3736
3749
|
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 -
|
|
3750
|
+
/* @__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
3751
|
);
|
|
3739
3752
|
}
|
|
3740
3753
|
return icons;
|
|
@@ -3755,8 +3768,8 @@ function TableInner({
|
|
|
3755
3768
|
const context = canvas?.getContext("2d");
|
|
3756
3769
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3757
3770
|
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)) *
|
|
3771
|
+
const visibleActions = cell?.leaf || !cell ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth, headerActionSlotWidth) : null;
|
|
3772
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth : columnDraggable ? headerActionSlotWidth : 0;
|
|
3760
3773
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3761
3774
|
const maxTextWidth = Math.max(0, contentWidth2 - 20);
|
|
3762
3775
|
const textWidth = Math.min(titleWidth, maxTextWidth);
|
|
@@ -3777,12 +3790,17 @@ function TableInner({
|
|
|
3777
3790
|
} else if (action === "sort") {
|
|
3778
3791
|
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3779
3792
|
label = direction === "asc" ? labels.sortAsc : direction === "desc" ? labels.sortDesc : labels.sortBoth;
|
|
3780
|
-
|
|
3793
|
+
const visibleActions = getVisibleHeaderActions(column, cellWidth, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
3794
|
+
const right = cellLeft + cellWidth - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
3795
|
+
anchorX = right - headerActionSlotWidth / 2;
|
|
3781
3796
|
anchorLeft = anchorX;
|
|
3782
3797
|
} else if (action === "filter") {
|
|
3783
3798
|
const value = filterValues[column.key];
|
|
3784
3799
|
label = value ? labels.filterWithValue(value) : labels.filter;
|
|
3785
|
-
|
|
3800
|
+
const visibleActions = getVisibleHeaderActions(column, cellWidth, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
3801
|
+
let right = cellLeft + cellWidth - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
3802
|
+
if (visibleActions.sort) right -= headerActionSlotWidth;
|
|
3803
|
+
anchorX = right - headerActionSlotWidth / 2;
|
|
3786
3804
|
anchorLeft = anchorX;
|
|
3787
3805
|
}
|
|
3788
3806
|
const placement = anchorX + 328 > viewport.width ? "left" : "right";
|
|
@@ -3795,7 +3813,7 @@ function TableInner({
|
|
|
3795
3813
|
label,
|
|
3796
3814
|
placement
|
|
3797
3815
|
};
|
|
3798
|
-
}, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, metrics, scrollPosition.top, sortState, viewport.width]);
|
|
3816
|
+
}, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, measureHeaderTitleWidth, metrics, scrollPosition.top, sortState, viewport.width]);
|
|
3799
3817
|
const isPointerOnHeaderTitle = (0, import_react5.useCallback)((clientX, clientY, cell) => {
|
|
3800
3818
|
const canvas = canvasRef.current;
|
|
3801
3819
|
if (!canvas) return false;
|
|
@@ -3809,14 +3827,14 @@ function TableInner({
|
|
|
3809
3827
|
const context = canvas.getContext("2d");
|
|
3810
3828
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3811
3829
|
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)) *
|
|
3830
|
+
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth, headerActionSlotWidth) : null;
|
|
3831
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth : columnDraggable ? headerActionSlotWidth : 0;
|
|
3814
3832
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3815
3833
|
const textWidth = Math.min(titleWidth, Math.max(0, contentWidth2 - 20));
|
|
3816
3834
|
const textLeft = column.align === "right" ? cellLeft + contentWidth2 - 10 - textWidth : column.align === "center" ? cellLeft + contentWidth2 / 2 - textWidth / 2 : cellLeft + 10;
|
|
3817
3835
|
const textTop = rowTop + 8;
|
|
3818
3836
|
return localX >= textLeft - 4 && localX <= textLeft + textWidth + 4 && localY >= textTop - 2 && localY <= textTop + 18;
|
|
3819
|
-
}, [columnDraggable, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerRowOffsets]);
|
|
3837
|
+
}, [columnDraggable, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, headerRowOffsets]);
|
|
3820
3838
|
const headerTooltip = (() => {
|
|
3821
3839
|
if (!visibleHeaderTooltip) return null;
|
|
3822
3840
|
return visibleHeaderTooltip;
|
|
@@ -4139,8 +4157,8 @@ function TableInner({
|
|
|
4139
4157
|
);
|
|
4140
4158
|
}
|
|
4141
4159
|
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)) *
|
|
4160
|
+
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
4161
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth;
|
|
4144
4162
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4145
4163
|
"div",
|
|
4146
4164
|
{
|
|
@@ -4184,13 +4202,13 @@ function TableInner({
|
|
|
4184
4202
|
const headerTop = (fixedHeader ? 0 : -currentScrollTop) + (headerRowOffsets[cell.level] ?? 0);
|
|
4185
4203
|
const left = fixedSide === "left" ? leftFixedOffsets.get(cell.startIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(cell.startIndex) ?? 0) - startMetric.width : getScrollableColumnLeft(cell.startIndex);
|
|
4186
4204
|
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)) *
|
|
4205
|
+
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, startMetric.width, columnDraggable, measureHeaderTitleWidth(cell.startIndex), headerActionSlotWidth) : null;
|
|
4206
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth : columnDraggable && !cell.leaf ? headerActionSlotWidth : 0;
|
|
4189
4207
|
const isDropTarget = Boolean(columnDropTarget && cell.endIndex >= columnDropTarget.startIndex && cell.startIndex <= columnDropTarget.endIndex);
|
|
4190
4208
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
4191
4209
|
"div",
|
|
4192
4210
|
{
|
|
4193
|
-
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}${isDropTarget ? " is-drop-target" : ""}`,
|
|
4211
|
+
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
4212
|
"data-level": cell.level,
|
|
4195
4213
|
"data-measure-key": `group:${cell.key}:${cell.level}`,
|
|
4196
4214
|
style: {
|
|
@@ -4221,7 +4239,7 @@ function TableInner({
|
|
|
4221
4239
|
HeaderDragIcon,
|
|
4222
4240
|
{
|
|
4223
4241
|
className: `rvg-header-icon rvg-header-drag-icon${hoveredHeaderAction?.columnIndex === cell.startIndex && hoveredHeaderAction.action === "drag" ? " is-hovered" : ""}`,
|
|
4224
|
-
style: { left: width2 -
|
|
4242
|
+
style: { left: width2 - headerActionSlotWidth, top: (rowHeightForLevel - headerActionSize) / 2 }
|
|
4225
4243
|
}
|
|
4226
4244
|
)
|
|
4227
4245
|
]
|
|
@@ -4487,12 +4505,13 @@ function TableInner({
|
|
|
4487
4505
|
width,
|
|
4488
4506
|
height: autoHeight ? effectiveHeight : height,
|
|
4489
4507
|
minHeight: autoHeight || typeof height === "number" ? void 0 : FALLBACK_HEIGHT,
|
|
4508
|
+
"--rvg-header-action-size": `${headerActionSize}px`,
|
|
4490
4509
|
...stripedColor ? { "--rvg-color-stripe": stripedColor } : null,
|
|
4491
4510
|
...style
|
|
4492
4511
|
};
|
|
4493
4512
|
const currentScroll = scrollRef.current;
|
|
4494
4513
|
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: [
|
|
4514
|
+
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
4515
|
/* @__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
4516
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4498
4517
|
"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, 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);
|
|
@@ -1175,14 +1177,16 @@ function paintGrid(options) {
|
|
|
1175
1177
|
ctx.fillRect(x, headerY, metric.width, headerHeight);
|
|
1176
1178
|
}
|
|
1177
1179
|
ctx.fillStyle = colors.grid;
|
|
1178
|
-
if (!verticalBorderless
|
|
1180
|
+
if (!verticalBorderless && !(frameBorderless && columnIndex === columns.length - 1)) {
|
|
1181
|
+
ctx.fillRect(x + metric.width - 1, headerY, 1, headerHeight);
|
|
1182
|
+
}
|
|
1179
1183
|
if (!horizontalBorderless) ctx.fillRect(x, headerY + headerHeight - 1, metric.width, 1);
|
|
1180
1184
|
const column = columns[columnIndex];
|
|
1181
1185
|
if (headerLeafTop === 0 && !column.rowSelection && !column.rowDragHandle && !column.rowNumber && !column.renderHeader && column.title) {
|
|
1182
1186
|
ctx.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
1183
1187
|
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)) *
|
|
1188
|
+
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth, headerActionSlotWidth);
|
|
1189
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth;
|
|
1186
1190
|
const contentWidth = Math.max(0, metric.width - actionWidth);
|
|
1187
1191
|
const padding = 10;
|
|
1188
1192
|
const clipWidth = contentWidth;
|
|
@@ -1212,12 +1216,12 @@ function paintGrid(options) {
|
|
|
1212
1216
|
ctx.fillRect(rightFixedLeft - 1, 0, 1, height);
|
|
1213
1217
|
}
|
|
1214
1218
|
ctx.fillStyle = colors.grid;
|
|
1215
|
-
if (!horizontalBorderless) ctx.fillRect(0, 0, width, 1);
|
|
1216
|
-
if (!verticalBorderless) {
|
|
1219
|
+
if (!horizontalBorderless && !frameBorderless) ctx.fillRect(0, 0, width, 1);
|
|
1220
|
+
if (!verticalBorderless && !frameBorderless) {
|
|
1217
1221
|
ctx.fillRect(0, 0, 1, height);
|
|
1218
1222
|
ctx.fillRect(width - 1, 0, 1, height);
|
|
1219
1223
|
}
|
|
1220
|
-
if (!horizontalBorderless && !options.suppressFrameBottomBorder) ctx.fillRect(0, height - 1, width, 1);
|
|
1224
|
+
if (!horizontalBorderless && !frameBorderless && !options.suppressFrameBottomBorder) ctx.fillRect(0, height - 1, width, 1);
|
|
1221
1225
|
if (selectionRange) {
|
|
1222
1226
|
const rowStart = Math.min(selectionRange.anchor.rowIndex, selectionRange.focus.rowIndex);
|
|
1223
1227
|
const rowEnd = Math.max(selectionRange.anchor.rowIndex, selectionRange.focus.rowIndex);
|
|
@@ -1526,6 +1530,7 @@ function TableInner({
|
|
|
1526
1530
|
borderless,
|
|
1527
1531
|
verticalBorderless,
|
|
1528
1532
|
horizontalBorderless = false,
|
|
1533
|
+
frameBorderless = false,
|
|
1529
1534
|
striped = false,
|
|
1530
1535
|
highlight,
|
|
1531
1536
|
cellSpans = [],
|
|
@@ -1572,6 +1577,8 @@ function TableInner({
|
|
|
1572
1577
|
setSourceColumns((current) => reconcileColumns(current, columnProps));
|
|
1573
1578
|
}, [columnProps]);
|
|
1574
1579
|
const rowHeight = layout?.rowHeight ?? rowHeightProp ?? 36;
|
|
1580
|
+
const headerActionSize = Math.max(8, layout?.headerActionSize ?? 14);
|
|
1581
|
+
const headerActionSlotWidth = headerActionSize + 2;
|
|
1575
1582
|
const baseHeaderHeight = layout?.headerHeight ?? headerHeightProp ?? 40;
|
|
1576
1583
|
const headerDepth = useMemo(() => Math.max(1, ...sourceColumns.map(getColumnDepth)), [sourceColumns]);
|
|
1577
1584
|
const { language, labels } = useMemo(() => resolveGridLocale(locale), [locale]);
|
|
@@ -2207,8 +2214,8 @@ function TableInner({
|
|
|
2207
2214
|
const scroll = scrollRef.current;
|
|
2208
2215
|
const rowScrollTop = fixedHeader ? scroll.top : Math.max(0, scroll.top - bodyTop);
|
|
2209
2216
|
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]);
|
|
2217
|
+
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, 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 });
|
|
2218
|
+
}, [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
2219
|
const scheduleDraw = useCallback2(() => {
|
|
2213
2220
|
if (frameRef.current === null) frameRef.current = requestAnimationFrame(draw);
|
|
2214
2221
|
}, [draw]);
|
|
@@ -2774,34 +2781,34 @@ function TableInner({
|
|
|
2774
2781
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return null;
|
|
2775
2782
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2776
2783
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2777
|
-
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex));
|
|
2778
|
-
let right = columnRight - (visibleActions.drag ?
|
|
2784
|
+
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
2785
|
+
let right = columnRight - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
2779
2786
|
if (visibleActions.sort) {
|
|
2780
|
-
if (localX >= right -
|
|
2781
|
-
right -=
|
|
2787
|
+
if (localX >= right - headerActionSlotWidth && localX < right) return "sort";
|
|
2788
|
+
right -= headerActionSlotWidth;
|
|
2782
2789
|
}
|
|
2783
|
-
if (visibleActions.filter && localX >= right -
|
|
2790
|
+
if (visibleActions.filter && localX >= right - headerActionSlotWidth && localX < right) return "filter";
|
|
2784
2791
|
return null;
|
|
2785
|
-
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2792
|
+
}, [columnDraggable, columns, getDisplayedColumnLeft, headerActionSlotWidth, measureHeaderTitleWidth, metrics]);
|
|
2786
2793
|
const isHeaderTitleTruncated = useCallback2((columnIndex) => {
|
|
2787
2794
|
const canvas = canvasRef.current;
|
|
2788
2795
|
if (columnIndex < 0 || !canvas) return false;
|
|
2789
2796
|
const column = columns[columnIndex];
|
|
2790
2797
|
const metric = metrics[columnIndex];
|
|
2791
2798
|
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)) *
|
|
2799
|
+
const visibleActions = getVisibleHeaderActions(column, metric.width, columnDraggable, titleWidth, headerActionSlotWidth);
|
|
2800
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth;
|
|
2794
2801
|
return getHeaderTitleRequiredWidth(column, titleWidth) > Math.max(0, metric.width - actionWidth);
|
|
2795
|
-
}, [columnDraggable, columns, measureHeaderTitleWidth, metrics]);
|
|
2802
|
+
}, [columnDraggable, columns, headerActionSlotWidth, measureHeaderTitleWidth, metrics]);
|
|
2796
2803
|
const locateHeaderDragHandle = useCallback2((clientX, columnIndex) => {
|
|
2797
2804
|
if (!columnDraggable || columnIndex < 0 || !canvasRef.current) return false;
|
|
2798
2805
|
const column = columns[columnIndex];
|
|
2799
2806
|
if (column.rowSelection || column.rowDragHandle || column.rowNumber) return false;
|
|
2800
|
-
if (!getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex)).drag) return false;
|
|
2807
|
+
if (!getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth).drag) return false;
|
|
2801
2808
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2802
2809
|
const columnRight = getDisplayedColumnLeft(columnIndex) + metrics[columnIndex].width;
|
|
2803
|
-
return localX >= columnRight -
|
|
2804
|
-
}, [columnDraggable, columns, getDisplayedColumnLeft, measureHeaderTitleWidth, metrics]);
|
|
2810
|
+
return localX >= columnRight - headerActionSlotWidth && localX < columnRight - 2;
|
|
2811
|
+
}, [columnDraggable, columns, getDisplayedColumnLeft, headerActionSlotWidth, measureHeaderTitleWidth, metrics]);
|
|
2805
2812
|
const getHeaderCellLeft = useCallback2((cell) => {
|
|
2806
2813
|
const startMetric = metrics[cell.startIndex];
|
|
2807
2814
|
const fixedSide = columns[cell.startIndex]?.fixed;
|
|
@@ -2866,8 +2873,8 @@ function TableInner({
|
|
|
2866
2873
|
if (cell.leaf) return locateHeaderDragHandle(clientX, cell.startIndex);
|
|
2867
2874
|
const localX = clientX - canvasRef.current.getBoundingClientRect().left;
|
|
2868
2875
|
const right = getHeaderCellLeft(cell) + getHeaderCellWidth(cell);
|
|
2869
|
-
return localX >= right -
|
|
2870
|
-
}, [columnDraggable, getHeaderCellLeft, getHeaderCellWidth, locateHeaderDragHandle]);
|
|
2876
|
+
return localX >= right - headerActionSlotWidth && localX < right - 2;
|
|
2877
|
+
}, [columnDraggable, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, locateHeaderDragHandle]);
|
|
2871
2878
|
const locateHeaderCell = useCallback2((clientX, clientY) => {
|
|
2872
2879
|
const canvas = canvasRef.current;
|
|
2873
2880
|
if (!canvas) return null;
|
|
@@ -3023,26 +3030,32 @@ function TableInner({
|
|
|
3023
3030
|
header.style.height = `${headerHeight}px`;
|
|
3024
3031
|
header.style.justifyContent = column.align === "right" ? "flex-end" : column.align === "center" ? "center" : "flex-start";
|
|
3025
3032
|
header.textContent = column.title;
|
|
3026
|
-
const visibleActions = getVisibleHeaderActions(column, columnWidth, columnDraggable, measureHeaderTitleWidth(sourceIndex));
|
|
3033
|
+
const visibleActions = getVisibleHeaderActions(column, columnWidth, columnDraggable, measureHeaderTitleWidth(sourceIndex), headerActionSlotWidth);
|
|
3027
3034
|
let actionRight = 2;
|
|
3028
3035
|
if (visibleActions.drag) {
|
|
3029
3036
|
const icon = createHeaderDragHandleSvg();
|
|
3030
3037
|
icon.classList.add("rvg-preview-header-icon");
|
|
3038
|
+
icon.style.width = `${headerActionSize}px`;
|
|
3039
|
+
icon.style.height = `${headerActionSize}px`;
|
|
3031
3040
|
icon.style.right = `${actionRight}px`;
|
|
3032
3041
|
header.appendChild(icon);
|
|
3033
|
-
actionRight +=
|
|
3042
|
+
actionRight += headerActionSlotWidth;
|
|
3034
3043
|
}
|
|
3035
3044
|
if (visibleActions.sort) {
|
|
3036
3045
|
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3037
3046
|
const icon = createHeaderSortSvg(direction);
|
|
3038
3047
|
icon.classList.add("rvg-preview-header-icon");
|
|
3048
|
+
icon.style.width = `${headerActionSize}px`;
|
|
3049
|
+
icon.style.height = `${headerActionSize}px`;
|
|
3039
3050
|
icon.style.right = `${actionRight}px`;
|
|
3040
3051
|
header.appendChild(icon);
|
|
3041
|
-
actionRight +=
|
|
3052
|
+
actionRight += headerActionSlotWidth;
|
|
3042
3053
|
}
|
|
3043
3054
|
if (visibleActions.filter) {
|
|
3044
3055
|
const icon = createHeaderSearchSvg(Boolean(filterValues[column.key]));
|
|
3045
3056
|
icon.classList.add("rvg-preview-header-icon", "rvg-preview-header-search-icon");
|
|
3057
|
+
icon.style.width = `${headerActionSize}px`;
|
|
3058
|
+
icon.style.height = `${headerActionSize}px`;
|
|
3046
3059
|
icon.style.right = `${actionRight}px`;
|
|
3047
3060
|
header.appendChild(icon);
|
|
3048
3061
|
}
|
|
@@ -3239,7 +3252,7 @@ function TableInner({
|
|
|
3239
3252
|
cleanupDrag();
|
|
3240
3253
|
cleanupDrop();
|
|
3241
3254
|
};
|
|
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]);
|
|
3255
|
+
}, [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
3256
|
const locateCell = useCallback2((clientX, clientY) => {
|
|
3244
3257
|
const canvas = canvasRef.current;
|
|
3245
3258
|
if (!canvas) return null;
|
|
@@ -3683,28 +3696,28 @@ function TableInner({
|
|
|
3683
3696
|
const renderHeaderIcons = (columnIndex, left) => {
|
|
3684
3697
|
const column = columns[columnIndex];
|
|
3685
3698
|
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 ?
|
|
3699
|
+
const top = headerLeafTop + (headerLeafHeight - headerActionSize) / 2;
|
|
3700
|
+
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
3701
|
+
let right = left + metrics[columnIndex].width - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
3689
3702
|
const icons = [];
|
|
3690
3703
|
if (visibleActions.drag) {
|
|
3691
3704
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "drag";
|
|
3692
3705
|
icons.push(
|
|
3693
|
-
/* @__PURE__ */ jsx7(HeaderDragIcon, { className: `rvg-header-icon rvg-header-drag-icon${hovered ? " is-hovered" : ""}`, style: { left: left + metrics[columnIndex].width -
|
|
3706
|
+
/* @__PURE__ */ jsx7(HeaderDragIcon, { className: `rvg-header-icon rvg-header-drag-icon${hovered ? " is-hovered" : ""}`, style: { left: left + metrics[columnIndex].width - headerActionSlotWidth, top } }, "drag")
|
|
3694
3707
|
);
|
|
3695
3708
|
}
|
|
3696
3709
|
if (visibleActions.sort) {
|
|
3697
3710
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "sort";
|
|
3698
3711
|
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3699
3712
|
icons.push(
|
|
3700
|
-
/* @__PURE__ */ jsx7(HeaderSortIcon, { className: `rvg-header-icon${hovered ? " is-hovered" : ""}`, style: { left: right -
|
|
3713
|
+
/* @__PURE__ */ jsx7(HeaderSortIcon, { className: `rvg-header-icon${hovered ? " is-hovered" : ""}`, style: { left: right - headerActionSlotWidth, top }, direction }, "sort")
|
|
3701
3714
|
);
|
|
3702
|
-
right -=
|
|
3715
|
+
right -= headerActionSlotWidth;
|
|
3703
3716
|
}
|
|
3704
3717
|
if (visibleActions.filter) {
|
|
3705
3718
|
const hovered = hoveredHeaderAction?.columnIndex === columnIndex && hoveredHeaderAction.action === "filter";
|
|
3706
3719
|
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 -
|
|
3720
|
+
/* @__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
3721
|
);
|
|
3709
3722
|
}
|
|
3710
3723
|
return icons;
|
|
@@ -3725,8 +3738,8 @@ function TableInner({
|
|
|
3725
3738
|
const context = canvas?.getContext("2d");
|
|
3726
3739
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3727
3740
|
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)) *
|
|
3741
|
+
const visibleActions = cell?.leaf || !cell ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth, headerActionSlotWidth) : null;
|
|
3742
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth : columnDraggable ? headerActionSlotWidth : 0;
|
|
3730
3743
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3731
3744
|
const maxTextWidth = Math.max(0, contentWidth2 - 20);
|
|
3732
3745
|
const textWidth = Math.min(titleWidth, maxTextWidth);
|
|
@@ -3747,12 +3760,17 @@ function TableInner({
|
|
|
3747
3760
|
} else if (action === "sort") {
|
|
3748
3761
|
const direction = sortState?.columnKey === column.key ? sortState.direction : null;
|
|
3749
3762
|
label = direction === "asc" ? labels.sortAsc : direction === "desc" ? labels.sortDesc : labels.sortBoth;
|
|
3750
|
-
|
|
3763
|
+
const visibleActions = getVisibleHeaderActions(column, cellWidth, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
3764
|
+
const right = cellLeft + cellWidth - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
3765
|
+
anchorX = right - headerActionSlotWidth / 2;
|
|
3751
3766
|
anchorLeft = anchorX;
|
|
3752
3767
|
} else if (action === "filter") {
|
|
3753
3768
|
const value = filterValues[column.key];
|
|
3754
3769
|
label = value ? labels.filterWithValue(value) : labels.filter;
|
|
3755
|
-
|
|
3770
|
+
const visibleActions = getVisibleHeaderActions(column, cellWidth, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
3771
|
+
let right = cellLeft + cellWidth - (visibleActions.drag ? headerActionSlotWidth : 2);
|
|
3772
|
+
if (visibleActions.sort) right -= headerActionSlotWidth;
|
|
3773
|
+
anchorX = right - headerActionSlotWidth / 2;
|
|
3756
3774
|
anchorLeft = anchorX;
|
|
3757
3775
|
}
|
|
3758
3776
|
const placement = anchorX + 328 > viewport.width ? "left" : "right";
|
|
@@ -3765,7 +3783,7 @@ function TableInner({
|
|
|
3765
3783
|
label,
|
|
3766
3784
|
placement
|
|
3767
3785
|
};
|
|
3768
|
-
}, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, metrics, scrollPosition.top, sortState, viewport.width]);
|
|
3786
|
+
}, [baseHeaderHeight, columnDraggable, columns, filterValues, fixedHeader, getDisplayedColumnLeft, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, headerDepth, headerRowHeights, headerRowOffsets, labels, measureHeaderTitleWidth, metrics, scrollPosition.top, sortState, viewport.width]);
|
|
3769
3787
|
const isPointerOnHeaderTitle = useCallback2((clientX, clientY, cell) => {
|
|
3770
3788
|
const canvas = canvasRef.current;
|
|
3771
3789
|
if (!canvas) return false;
|
|
@@ -3779,14 +3797,14 @@ function TableInner({
|
|
|
3779
3797
|
const context = canvas.getContext("2d");
|
|
3780
3798
|
if (context) context.font = "600 13px Inter, ui-sans-serif, system-ui, sans-serif";
|
|
3781
3799
|
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)) *
|
|
3800
|
+
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, cellWidth, columnDraggable, titleWidth, headerActionSlotWidth) : null;
|
|
3801
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth : columnDraggable ? headerActionSlotWidth : 0;
|
|
3784
3802
|
const contentWidth2 = Math.max(0, cellWidth - actionWidth);
|
|
3785
3803
|
const textWidth = Math.min(titleWidth, Math.max(0, contentWidth2 - 20));
|
|
3786
3804
|
const textLeft = column.align === "right" ? cellLeft + contentWidth2 - 10 - textWidth : column.align === "center" ? cellLeft + contentWidth2 / 2 - textWidth / 2 : cellLeft + 10;
|
|
3787
3805
|
const textTop = rowTop + 8;
|
|
3788
3806
|
return localX >= textLeft - 4 && localX <= textLeft + textWidth + 4 && localY >= textTop - 2 && localY <= textTop + 18;
|
|
3789
|
-
}, [columnDraggable, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerRowOffsets]);
|
|
3807
|
+
}, [columnDraggable, fixedHeader, getHeaderCellLeft, getHeaderCellWidth, headerActionSlotWidth, headerRowOffsets]);
|
|
3790
3808
|
const headerTooltip = (() => {
|
|
3791
3809
|
if (!visibleHeaderTooltip) return null;
|
|
3792
3810
|
return visibleHeaderTooltip;
|
|
@@ -4109,8 +4127,8 @@ function TableInner({
|
|
|
4109
4127
|
);
|
|
4110
4128
|
}
|
|
4111
4129
|
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)) *
|
|
4130
|
+
const visibleActions = getVisibleHeaderActions(column, metrics[columnIndex].width, columnDraggable, measureHeaderTitleWidth(columnIndex), headerActionSlotWidth);
|
|
4131
|
+
const actionWidth = (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth;
|
|
4114
4132
|
return /* @__PURE__ */ jsx7(
|
|
4115
4133
|
"div",
|
|
4116
4134
|
{
|
|
@@ -4154,13 +4172,13 @@ function TableInner({
|
|
|
4154
4172
|
const headerTop = (fixedHeader ? 0 : -currentScrollTop) + (headerRowOffsets[cell.level] ?? 0);
|
|
4155
4173
|
const left = fixedSide === "left" ? leftFixedOffsets.get(cell.startIndex) ?? 0 : fixedSide === "right" ? viewport.width - (rightFixedOffsets.get(cell.startIndex) ?? 0) - startMetric.width : getScrollableColumnLeft(cell.startIndex);
|
|
4156
4174
|
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)) *
|
|
4175
|
+
const visibleActions = cell.leaf ? getVisibleHeaderActions(column, startMetric.width, columnDraggable, measureHeaderTitleWidth(cell.startIndex), headerActionSlotWidth) : null;
|
|
4176
|
+
const actionWidth = visibleActions ? (Number(visibleActions.drag) + Number(visibleActions.filter) + Number(visibleActions.sort)) * headerActionSlotWidth : columnDraggable && !cell.leaf ? headerActionSlotWidth : 0;
|
|
4159
4177
|
const isDropTarget = Boolean(columnDropTarget && cell.endIndex >= columnDropTarget.startIndex && cell.startIndex <= columnDropTarget.endIndex);
|
|
4160
4178
|
return /* @__PURE__ */ jsxs7(
|
|
4161
4179
|
"div",
|
|
4162
4180
|
{
|
|
4163
|
-
className: `rvg-header-title rvg-header-group${column.renderHeader ? " is-custom" : ""}${cell.leaf ? " is-leaf" : ""}${isDropTarget ? " is-drop-target" : ""}`,
|
|
4181
|
+
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
4182
|
"data-level": cell.level,
|
|
4165
4183
|
"data-measure-key": `group:${cell.key}:${cell.level}`,
|
|
4166
4184
|
style: {
|
|
@@ -4191,7 +4209,7 @@ function TableInner({
|
|
|
4191
4209
|
HeaderDragIcon,
|
|
4192
4210
|
{
|
|
4193
4211
|
className: `rvg-header-icon rvg-header-drag-icon${hoveredHeaderAction?.columnIndex === cell.startIndex && hoveredHeaderAction.action === "drag" ? " is-hovered" : ""}`,
|
|
4194
|
-
style: { left: width2 -
|
|
4212
|
+
style: { left: width2 - headerActionSlotWidth, top: (rowHeightForLevel - headerActionSize) / 2 }
|
|
4195
4213
|
}
|
|
4196
4214
|
)
|
|
4197
4215
|
]
|
|
@@ -4457,12 +4475,13 @@ function TableInner({
|
|
|
4457
4475
|
width,
|
|
4458
4476
|
height: autoHeight ? effectiveHeight : height,
|
|
4459
4477
|
minHeight: autoHeight || typeof height === "number" ? void 0 : FALLBACK_HEIGHT,
|
|
4478
|
+
"--rvg-header-action-size": `${headerActionSize}px`,
|
|
4460
4479
|
...stripedColor ? { "--rvg-color-stripe": stripedColor } : null,
|
|
4461
4480
|
...style
|
|
4462
4481
|
};
|
|
4463
4482
|
const currentScroll = scrollRef.current;
|
|
4464
4483
|
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: [
|
|
4484
|
+
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
4485
|
/* @__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
4486
|
/* @__PURE__ */ jsx7(
|
|
4468
4487
|
"canvas",
|