|
|
|
|
/**
|
|
|
|
|
* usePretextRowHeights
|
|
|
|
|
*
|
|
|
|
|
* Pre-computes row heights using pretext text measurement.
|
|
|
|
|
* For each row, measures each cell's height at the given column width,
|
|
|
|
|
* then takes the maximum + padding as the row height.
|
|
|
|
|
*/
|
|
|
|
|
import { computed, type Ref } from "vue";
|
|
|
|
|
import { measureTextHeight } from "./measureText";
|
|
|
|
|
import type { ListTableColumn } from "./types";
|
|
|
|
|
import { toRefs } from "@vueuse/core";
|
|
|
|
|
|
|
|
|
|
export interface RowHeightEntry {
|
|
|
|
|
height: number;
|
|
|
|
|
isCustomRenderer: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function resolveRowHeights<T>(
|
|
|
|
|
data: Ref<T[]>,
|
|
|
|
|
columns: Ref<ListTableColumn<T>[]>,
|
|
|
|
|
columnWidths: Ref<number[]>,
|
|
|
|
|
lineMaxWidth: number,
|
|
|
|
|
formatCellValue: (row: T, col: ListTableColumn<T>) => string,
|
|
|
|
|
style: {
|
|
|
|
|
font: string;
|
|
|
|
|
lineHeight: number;
|
|
|
|
|
padding: { top: number; bottom: number; left: number; right: number };
|
|
|
|
|
},
|
|
|
|
|
options?: {
|
|
|
|
|
fixedRowHeight?: number;
|
|
|
|
|
debug?: boolean;
|
|
|
|
|
}
|
|
|
|
|
) {
|
|
|
|
|
const { font, lineHeight, padding } = style;
|
|
|
|
|
|
|
|
|
|
const { rowHeights, cellHeights } = toRefs(
|
|
|
|
|
computed(() => {
|
|
|
|
|
if (!data.value.length || !columns.value.length || !columnWidths.value.length) {
|
|
|
|
|
return { rowHeights: [], cellHeights: [] };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const rowHeights: number[] = [];
|
|
|
|
|
const cellHeights: Array<RowHeightEntry | null>[] | undefined = options?.debug ? [] : undefined;
|
|
|
|
|
|
|
|
|
|
for (const row of data.value) {
|
|
|
|
|
let maxCellHeight = lineHeight; // minimum 1 line
|
|
|
|
|
let rowCellHeights: Array<RowHeightEntry | null> = [];
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < columns.value.length; i++) {
|
|
|
|
|
const col = columns.value[i];
|
|
|
|
|
// Use flex basis width for height calculation as an approximation
|
|
|
|
|
// of actual column width (CSS flex layout determines actual width)
|
|
|
|
|
const colWidth = columnWidths.value[i] ?? 120;
|
|
|
|
|
|
|
|
|
|
// Check if custom renderer exists (we can't measure these with pretext)
|
|
|
|
|
const isCustomRenderer = !!(col.cellRenderer || col.slot);
|
|
|
|
|
let rowHeightEntry: RowHeightEntry;
|
|
|
|
|
|
|
|
|
|
if (options?.fixedRowHeight) {
|
|
|
|
|
rowHeightEntry = {
|
|
|
|
|
height: options.fixedRowHeight,
|
|
|
|
|
isCustomRenderer,
|
|
|
|
|
};
|
|
|
|
|
} else if (isCustomRenderer) {
|
|
|
|
|
rowHeightEntry = {
|
|
|
|
|
height: 42,
|
|
|
|
|
isCustomRenderer,
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
try {
|
|
|
|
|
const cellText = formatCellValue(row, col);
|
|
|
|
|
if (!cellText) throw "Invalid Cell Text";
|
|
|
|
|
|
|
|
|
|
// Calculate available width for text (excluding cell padding)
|
|
|
|
|
const availableWidth = Math.min(
|
|
|
|
|
colWidth - padding.left - padding.right,
|
|
|
|
|
col.maxTextWidth ?? lineMaxWidth
|
|
|
|
|
);
|
|
|
|
|
if (availableWidth <= 0) throw "Invalid Column Width";
|
|
|
|
|
|
|
|
|
|
rowHeightEntry = {
|
|
|
|
|
height: measureTextHeight(cellText, font, availableWidth, lineHeight),
|
|
|
|
|
isCustomRenderer,
|
|
|
|
|
};
|
|
|
|
|
} catch {
|
|
|
|
|
// Fallback: assume single line
|
|
|
|
|
rowHeightEntry = {
|
|
|
|
|
height: 42,
|
|
|
|
|
isCustomRenderer,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
maxCellHeight = Math.max(maxCellHeight, rowHeightEntry?.height ?? 0);
|
|
|
|
|
if (options?.debug) {
|
|
|
|
|
rowCellHeights.push(rowHeightEntry);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const rowHeight = maxCellHeight + padding.top + padding.bottom;
|
|
|
|
|
rowHeights.push(rowHeight);
|
|
|
|
|
cellHeights?.push(rowCellHeights);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
rowHeights,
|
|
|
|
|
cellHeights,
|
|
|
|
|
};
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Total height (sum of all row heights) - useful for virtualizer
|
|
|
|
|
const totalHeight = computed(() => rowHeights.value.reduce((sum, height) => sum + height, 0));
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
rowHeights,
|
|
|
|
|
totalHeight,
|
|
|
|
|
cellHeights,
|
|
|
|
|
};
|
|
|
|
|
}
|