import type { ColumnDef, ColumnSizingState, RowData, Table, TableState, Updater } from '@tanstack/table-core'; import { sum } from 'lodash-es'; import { ACTIONS_COLUMN_ID, MEMOIZED_HANDLE_ID } from './constants.ts'; import { DataTableRowActionCell } from './DataTableRowActionCell.tsx'; import type { BaseDataTableStoreParams, DataTableColumnBreakpoints, DataTableStoreParams, MemoizedHandle } from './types.ts'; const DEFAULT_COLUMN_BREAKPOINTS: DataTableColumnBreakpoints = { 0: 1, 512: 2, 768: 3, 1024: 4, 1280: 5 }; function applyUpdater(updater: Updater, current: T): T { return typeof updater === 'function' ? (updater as (prev: T) => T)(current) : updater; } function calculateColumnSizing( table: Table, containerWidth: number, breakpoints: DataTableColumnBreakpoints = DEFAULT_COLUMN_BREAKPOINTS ) { const updatedColumnSizing: ColumnSizingState = {}; const visibleCenterLeafColumns = table.getCenterLeafColumns().filter((column) => column.getIsVisible()); const visibleCenterLeafColumnIds = visibleCenterLeafColumns.map((column) => column.id); const visibleNonCenteredLeafColumns = table.getVisibleLeafColumns().filter((column) => { return !visibleCenterLeafColumnIds.includes(column.id); }); visibleNonCenteredLeafColumns.forEach((column) => { const defaultSize = column.columnDef.size; if (!defaultSize) { console.error(`Size must be specified for pinned column with ID '${column.id}', defaulting to 200px`); updatedColumnSizing[column.id] = 200; } else { updatedColumnSizing[column.id] = defaultSize; } }); const nonCenteredColumnsSize = sum(Object.values(updatedColumnSizing)); const availableCenterSize = containerWidth - nonCenteredColumnsSize; let maxCenterColumns: number; if (containerWidth < 512) { maxCenterColumns = breakpoints[0]; } else if (containerWidth < 768) { maxCenterColumns = breakpoints[512]; } else if (containerWidth < 1024) { maxCenterColumns = breakpoints[768]; } else if (containerWidth < 1280) { maxCenterColumns = breakpoints[1024]; } else { maxCenterColumns = breakpoints[1280]; } const centerColumnsToDisplay = Math.min(visibleCenterLeafColumns.length, maxCenterColumns); if (centerColumnsToDisplay) { visibleCenterLeafColumns.forEach((column) => { updatedColumnSizing[column.id] = availableCenterSize / centerColumnsToDisplay; }); } else { visibleNonCenteredLeafColumns.forEach((column) => { updatedColumnSizing[column.id] = containerWidth / visibleNonCenteredLeafColumns.length; }); } return updatedColumnSizing; } function defineMemoizedHandle any>(target: T) { const handle = target as MemoizedHandle; handle[MEMOIZED_HANDLE_ID] = Symbol(); handle.invalidate = function () { this[MEMOIZED_HANDLE_ID] = Symbol(); }; return handle; } function flexRender( Comp: React.ComponentType | React.ReactNode, props: TProps ): React.JSX.Element | React.ReactNode { return !Comp ? null : isReactComponent(Comp) ? : Comp; } function getColumnsWithActions({ columns, rowActions }: BaseDataTableStoreParams): ColumnDef[] { if (!rowActions) { return columns; } return [ ...columns, { cell: DataTableRowActionCell, enableHiding: false, enableResizing: false, id: ACTIONS_COLUMN_ID, size: 64 } ]; } function getTanstackTableState({ initialState, rowActions }: DataTableStoreParams): TableState { const { columnFilters = [], columnPinning = {}, sorting = [] } = initialState ?? {}; const state: TableState = { columnFilters, columnOrder: [], columnPinning, columnSizing: {}, columnSizingInfo: { columnSizingStart: [], deltaOffset: null, deltaPercentage: null, isResizingColumn: false, startOffset: null, startSize: null }, columnVisibility: {}, expanded: {}, globalFilter: undefined, grouping: [], pagination: { pageIndex: 0, pageSize: 10 }, rowPinning: {}, rowSelection: {}, sorting }; if (rowActions) { state.columnPinning = { ...state.columnPinning, right: [...(state.columnPinning.right ?? []), ACTIONS_COLUMN_ID] }; } return state; } function isReactComponent(component: unknown): component is React.ComponentType { return typeof component === 'function'; } export { applyUpdater, calculateColumnSizing, defineMemoizedHandle, flexRender, getColumnsWithActions, getTanstackTableState };