mirror of
https://github.com/t8y2/dbx.git
synced 2026-11-01 08:26:35 +00:00
fix(grid): reserve header control width
This commit is contained in:
@@ -1,20 +1,15 @@
|
||||
import { ref, computed, type ComputedRef, type Ref } from "vue";
|
||||
import { useElementSize } from "@vueuse/core";
|
||||
import {
|
||||
calculateDataGridColumnWidth,
|
||||
DATA_GRID_COL_MIN_WIDTH,
|
||||
DATA_GRID_SAMPLE_ROWS,
|
||||
} from "@/lib/dataGridColumnWidth";
|
||||
|
||||
type CellValue = string | number | boolean | null;
|
||||
|
||||
export const COL_MIN_WIDTH = 60;
|
||||
export const COL_MAX_WIDTH = 400;
|
||||
const COL_CHAR_WIDTH = 8;
|
||||
const COL_HEADER_PADDING = 48;
|
||||
const COL_CELL_PADDING = 28;
|
||||
const COL_SAMPLE_ROWS = 50;
|
||||
const ROW_NUM_WIDTH = 48;
|
||||
|
||||
function estimateTextWidth(text: string, padding: number): number {
|
||||
return text.length * COL_CHAR_WIDTH + padding;
|
||||
}
|
||||
|
||||
export interface UseDataGridColumnResizeOptions {
|
||||
columns: ComputedRef<string[]>;
|
||||
rows: ComputedRef<CellValue[][]>;
|
||||
@@ -28,21 +23,18 @@ export function useDataGridColumnResize(options: UseDataGridColumnResizeOptions)
|
||||
const { width: gridWidth } = useElementSize(gridRef);
|
||||
let isResizing = false;
|
||||
|
||||
function sampleColumnValues(rowData: CellValue[][], colIdx: number): CellValue[] {
|
||||
return rowData.slice(0, DATA_GRID_SAMPLE_ROWS).map((row) => row[colIdx] ?? null);
|
||||
}
|
||||
|
||||
function initColumnWidths() {
|
||||
if (columnWidths.value.length !== columns.value.length) {
|
||||
const rowData = rows.value;
|
||||
const sampleCount = Math.min(rowData.length, COL_SAMPLE_ROWS);
|
||||
columnWidths.value = columns.value.map((colName, colIdx) => {
|
||||
let maxWidth = estimateTextWidth(colName, COL_HEADER_PADDING);
|
||||
for (let i = 0; i < sampleCount; i++) {
|
||||
const val = rowData[i]?.[colIdx];
|
||||
if (val == null) continue;
|
||||
const text = typeof val === "object" ? JSON.stringify(val) : String(val);
|
||||
const displayLen = Math.min(text.length, 60);
|
||||
const w = displayLen * COL_CHAR_WIDTH + COL_CELL_PADDING;
|
||||
if (w > maxWidth) maxWidth = w;
|
||||
}
|
||||
return Math.max(COL_MIN_WIDTH, Math.min(COL_MAX_WIDTH, Math.round(maxWidth)));
|
||||
return calculateDataGridColumnWidth({
|
||||
columnName: colName,
|
||||
sampleValues: sampleColumnValues(rowData, colIdx),
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -53,7 +45,7 @@ export function useDataGridColumnResize(options: UseDataGridColumnResizeOptions)
|
||||
const startX = event.clientX;
|
||||
const startWidth = columnWidths.value[colIdx];
|
||||
const onMove = (e: MouseEvent) => {
|
||||
columnWidths.value[colIdx] = Math.max(60, startWidth + e.clientX - startX);
|
||||
columnWidths.value[colIdx] = Math.max(DATA_GRID_COL_MIN_WIDTH, startWidth + e.clientX - startX);
|
||||
};
|
||||
const onUp = () => {
|
||||
document.removeEventListener("mousemove", onMove);
|
||||
@@ -70,17 +62,10 @@ export function useDataGridColumnResize(options: UseDataGridColumnResizeOptions)
|
||||
const colName = columns.value[colIdx];
|
||||
if (!colName) return;
|
||||
const rowData = rows.value;
|
||||
const sampleCount = Math.min(rowData.length, COL_SAMPLE_ROWS);
|
||||
let maxWidth = estimateTextWidth(colName, COL_HEADER_PADDING);
|
||||
for (let i = 0; i < sampleCount; i++) {
|
||||
const val = rowData[i]?.[colIdx];
|
||||
if (val == null) continue;
|
||||
const text = typeof val === "object" ? JSON.stringify(val) : String(val);
|
||||
const displayLen = Math.min(text.length, 60);
|
||||
const w = displayLen * COL_CHAR_WIDTH + COL_CELL_PADDING;
|
||||
if (w > maxWidth) maxWidth = w;
|
||||
}
|
||||
columnWidths.value[colIdx] = Math.max(COL_MIN_WIDTH, Math.min(COL_MAX_WIDTH, Math.round(maxWidth)));
|
||||
columnWidths.value[colIdx] = calculateDataGridColumnWidth({
|
||||
columnName: colName,
|
||||
sampleValues: sampleColumnValues(rowData, colIdx),
|
||||
});
|
||||
}
|
||||
|
||||
const baseTotalWidth = computed(() => columnWidths.value.reduce((a, b) => a + b, 0));
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
type CellValue = string | number | boolean | null;
|
||||
|
||||
export const DATA_GRID_COL_MIN_WIDTH = 60;
|
||||
export const DATA_GRID_COL_MAX_WIDTH = 400;
|
||||
export const DATA_GRID_CHAR_WIDTH = 8;
|
||||
export const DATA_GRID_HEADER_CONTROL_WIDTH = 64;
|
||||
export const DATA_GRID_CELL_PADDING = 28;
|
||||
export const DATA_GRID_SAMPLE_ROWS = 50;
|
||||
|
||||
function estimateTextWidth(text: string, padding: number): number {
|
||||
return text.length * DATA_GRID_CHAR_WIDTH + padding;
|
||||
}
|
||||
|
||||
function displaySampleValue(value: CellValue): string | null {
|
||||
if (value == null) return null;
|
||||
return typeof value === "object" ? JSON.stringify(value) : String(value);
|
||||
}
|
||||
|
||||
export function calculateDataGridColumnWidth(options: {
|
||||
columnName: string;
|
||||
sampleValues: readonly CellValue[];
|
||||
}): number {
|
||||
let maxWidth = estimateTextWidth(options.columnName, DATA_GRID_HEADER_CONTROL_WIDTH);
|
||||
|
||||
for (const value of options.sampleValues.slice(0, DATA_GRID_SAMPLE_ROWS)) {
|
||||
const text = displaySampleValue(value);
|
||||
if (text == null) continue;
|
||||
const displayLen = Math.min(text.length, 60);
|
||||
const width = displayLen * DATA_GRID_CHAR_WIDTH + DATA_GRID_CELL_PADDING;
|
||||
if (width > maxWidth) maxWidth = width;
|
||||
}
|
||||
|
||||
return Math.max(DATA_GRID_COL_MIN_WIDTH, Math.min(DATA_GRID_COL_MAX_WIDTH, Math.round(maxWidth)));
|
||||
}
|
||||
Reference in New Issue
Block a user