Bin
2025-12-16 9e0b2ba2c317b1a86212f24cbae3195ad1f3dbfa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import { type ColumnDef, createColumnHelper } from "@tanstack/react-table";
import type { DataShape, DataTableHeaders, DataTableCells, DataTableSizes } from "./data-table";
 
/**
 * Resolves the columns from the input data.
 * Applies ordering and filtering to the columns.
 */
export function resolveColumns<T extends DataShape>(
  data: T,
  headers?: DataTableHeaders<T>,
  cells?: DataTableCells<T>,
  sizes?: DataTableSizes<T>,
  includeColumns?: (keyof T[number])[],
  excludeColumns?: (keyof T[number])[],
  columnOrder?: (keyof T[number])[],
): ColumnDef<Record<string, unknown>, T[number][string]>[] {
  if (!data?.length) return [];
 
  const helper = createColumnHelper<DataShape[number]>();
  const keys = getDataKeys(Object.keys(data[0]), columnOrder as string[]);
  const finalColumns = filterColumns(keys, includeColumns, excludeColumns);
 
  return finalColumns.map((key) => {
    const header = headers?.[key] ?? key;
    const cell = cells?.[key] ?? cells?.restCells ?? ((info) => info.getValue() ?? "");
    const rest = sizes?.[key] ?? sizes?.restColumns ?? {};
 
    return helper.accessor(key, {
      id: key,
      header,
      cell,
      ...rest,
    });
  });
}
 
function filterColumns<T extends DataShape>(
  columns: string[],
  includeColumns?: (keyof T[number])[],
  excludeColumns?: (keyof T[number])[],
): string[] {
  if (includeColumns && includeColumns.length > 0) return columns.filter((column) => includeColumns.includes(column));
  if (excludeColumns && excludeColumns.length > 0) return columns.filter((column) => !excludeColumns.includes(column));
 
  return columns;
}
 
function getDataKeys(keys: string[], order?: string[]): string[] {
  if (order) {
    const list = [...order];
    const restKeys = keys.filter((key) => !list.includes(key));
    const restPosition = list.indexOf("#restColumns");
 
    if (restPosition > -1) {
      // replace placeholder with rest of the keys
      list.splice(restPosition, 1, ...restKeys);
    } else {
      // append rest of the keys to the end
      list.push(...restKeys);
    }
    return list;
  }
 
  return keys;
}
 
/**
 * Creates a CSS variable key for column sizing
 */
export const createColumnSizeKey = (type: "header" | "col", id: string) => {
  // Replace any whitespace or special characters with underscores
  const sanitizedId = id.replace(/[^a-zA-Z0-9]/g, "_");
  return `--${type}-${sanitizedId}-size`;
};