Files
feishin/src/renderer/components/item-list/item-table-list/hooks/use-table-column-model.ts
T
2026-01-16 23:45:19 -08:00

116 lines
4.1 KiB
TypeScript

import { useMemo } from 'react';
import { parseTableColumns } from '/@/renderer/components/item-list/helpers/parse-table-columns';
import { ItemTableListColumnConfig } from '/@/renderer/components/item-list/types';
export const useTableColumnModel = ({
autoFitColumns,
centerContainerWidth,
columns,
totalContainerWidth,
}: {
autoFitColumns: boolean;
centerContainerWidth: number;
columns: ItemTableListColumnConfig[];
totalContainerWidth: number;
}) => {
const parsedColumns = useMemo(() => parseTableColumns(columns), [columns]);
const calculatedColumnWidths = useMemo(() => {
const baseWidths = parsedColumns.map((c) => c.width);
// When autoSizeColumns is enabled, treat all widths as proportions and scale to fit container
if (autoFitColumns) {
const totalReferenceWidth = baseWidths.reduce((sum, width) => sum + width, 0);
if (totalReferenceWidth === 0 || totalContainerWidth === 0) {
return baseWidths.map((width) => Math.round(width));
}
const scaleFactor = totalContainerWidth / totalReferenceWidth;
const scaledWidths = baseWidths.map((width) => Math.round(width * scaleFactor));
// Adjust for rounding errors: ensure total equals totalContainerWidth
const totalScaled = scaledWidths.reduce((sum, width) => sum + width, 0);
const difference = totalContainerWidth - totalScaled;
if (difference !== 0 && scaledWidths.length > 0) {
const sortedIndices = scaledWidths
.map((width, idx) => ({ idx, width }))
.sort((a, b) => b.width - a.width);
const adjustmentPerColumn = Math.sign(difference);
const adjustmentCount = Math.abs(difference);
for (let i = 0; i < adjustmentCount && i < sortedIndices.length; i++) {
scaledWidths[sortedIndices[i].idx] += adjustmentPerColumn;
}
}
return scaledWidths;
}
// Original behavior: distribute extra space to auto-size columns
const distributed = baseWidths.slice();
const unpinnedIndices: number[] = [];
const autoUnpinnedIndices: number[] = [];
parsedColumns.forEach((col, idx) => {
if (col.pinned === null) {
unpinnedIndices.push(idx);
if (col.autoSize) {
autoUnpinnedIndices.push(idx);
}
}
});
if (unpinnedIndices.length === 0 || autoUnpinnedIndices.length === 0) {
return distributed.map((width) => Math.round(width));
}
const unpinnedBaseTotal = unpinnedIndices.reduce((sum, idx) => sum + baseWidths[idx], 0);
const extra = Math.max(0, centerContainerWidth - unpinnedBaseTotal);
if (extra <= 0) {
return distributed.map((width) => Math.round(width));
}
const extraPer = extra / autoUnpinnedIndices.length;
autoUnpinnedIndices.forEach((idx) => {
distributed[idx] = Math.round(baseWidths[idx] + extraPer);
});
return distributed.map((width) => Math.round(width));
}, [autoFitColumns, centerContainerWidth, parsedColumns, totalContainerWidth]);
const pinnedLeftColumnCount = useMemo(
() => parsedColumns.filter((col) => col.pinned === 'left').length,
[parsedColumns],
);
const pinnedRightColumnCount = useMemo(
() => parsedColumns.filter((col) => col.pinned === 'right').length,
[parsedColumns],
);
const columnCount = parsedColumns.length;
const totalColumnCount = columnCount - pinnedLeftColumnCount - pinnedRightColumnCount;
return useMemo(
() => ({
calculatedColumnWidths,
columnCount,
parsedColumns,
pinnedLeftColumnCount,
pinnedRightColumnCount,
totalColumnCount,
}),
[
calculatedColumnWidths,
columnCount,
parsedColumns,
pinnedLeftColumnCount,
pinnedRightColumnCount,
totalColumnCount,
],
);
};