import { useCallback, useEffect, useState } from 'react'; import type { ColumnMeta } from '@wellformed/shared'; const STORAGE_KEY = 'wellformed.columnWidths'; const MIN_WIDTH = 60; const MAX_WIDTH = 640; function defaultWidth(col: ColumnMeta): number { switch (col.type) { case 'checkbox': return 70; case 'date': return 118; case 'number': return 100; case 'currency': return 120; case 'select': return 120; case 'link': return 170; default: // The label is what the header actually renders, so it sizes the column. return col.label.length > 12 ? 190 : 150; } } type WidthMap = Record; function readStored(): WidthMap { try { const raw = window.localStorage.getItem(STORAGE_KEY); return raw ? (JSON.parse(raw) as WidthMap) : {}; } catch { return {}; } } /** * Per-column widths, remembered across sessions. Keyed by table and column so * two tables with a `Name` column keep their own sizing. */ export function useColumnWidths(table: string, columns: ColumnMeta[]) { const [stored, setStored] = useState(readStored); useEffect(() => { try { window.localStorage.setItem(STORAGE_KEY, JSON.stringify(stored)); } catch { // A full or disabled localStorage must not break the grid. } }, [stored]); const widthOf = useCallback( (col: ColumnMeta) => stored[`${table}.${col.name}`] ?? defaultWidth(col), [stored, table], ); const setWidth = useCallback( (col: ColumnMeta, width: number) => { const clamped = Math.round(Math.min(MAX_WIDTH, Math.max(MIN_WIDTH, width))); setStored((s) => ({ ...s, [`${table}.${col.name}`]: clamped })); }, [table], ); const reset = useCallback( (col: ColumnMeta) => { setStored((s) => { const next = { ...s }; delete next[`${table}.${col.name}`]; return next; }); }, [table], ); const widths = columns.map(widthOf); const totalWidth = widths.reduce((a, b) => a + b, 0) + 44; // + row-number gutter return { widthOf, setWidth, reset, widths, totalWidth, MIN_WIDTH }; }