diff --git a/src/components/DataTable/__tests__/DataTable.spec.tsx b/src/components/DataTable/__tests__/DataTable.spec.tsx index 0e16373..b9d34cb 100644 --- a/src/components/DataTable/__tests__/DataTable.spec.tsx +++ b/src/components/DataTable/__tests__/DataTable.spec.tsx @@ -3,7 +3,7 @@ import { useState } from 'react'; import { faker } from '@faker-js/faker'; import type { ColumnDef } from '@tanstack/table-core'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; -import { range } from 'lodash-es'; +import { noop, range } from 'lodash-es'; import { describe, expect, it } from 'vitest'; import { DataTable } from '../DataTable.tsx'; @@ -152,3 +152,25 @@ describe('DataTable pagination', () => { expect(screen.getAllByTestId('data-table-row').length).toBe(1); }); }); + +describe('DataTable server mode', () => { + const serverProps = { + columns, + data: data.slice(0, 10), + mode: 'server', + onPaginationChange: noop, + pageCount: 3 + } as const; + + it('should pin a column named by its initial state, so a server-mode table can size it', () => { + render(); + expect(screen.getByText('Amount')).toHaveStyle({ position: 'sticky' }); + expect(screen.getByText('Status')).not.toHaveStyle({ position: 'sticky' }); + expect(screen.getByText('Email')).not.toHaveStyle({ position: 'sticky' }); + }); + + it('should pin nothing when given no initial state', () => { + render(); + expect(screen.getByText('Amount')).not.toHaveStyle({ position: 'sticky' }); + }); +}); diff --git a/src/components/DataTable/types.ts b/src/components/DataTable/types.ts index a35c9eb..7ea4e68 100644 --- a/src/components/DataTable/types.ts +++ b/src/components/DataTable/types.ts @@ -96,11 +96,12 @@ export type MemoizedHandle any> = T & { * CLIENT *********************************************************************/ -export type ClientDataTableInitialState = { - columnFilters?: ColumnFiltersState; - columnPinning?: ColumnPinningState; - sorting?: SortingState; -}; +export type ClientDataTableInitialState = Simplify< + ServerDataTableInitialState & { + columnFilters?: ColumnFiltersState; + sorting?: SortingState; + } +>; export type ClientDataTableStoreParams = Simplify< BaseDataTableStoreParams & { @@ -117,9 +118,19 @@ export type ClientDataTableProps = Simplify< * SERVER *********************************************************************/ +/** + * Pinning is layout rather than a view of the data: `calculateColumnSizing` honours `size` on a + * pinned column and splits what is left between the rest, so it is how a table of any mode gives + * one column the room its content needs. Filtering and sorting in server mode belong to the + * request, so they stay out. + */ +export type ServerDataTableInitialState = { + columnPinning?: ColumnPinningState; +}; + export type ServerDataTableStoreParams = Simplify< BaseDataTableStoreParams & { - initialState?: never; + initialState?: ServerDataTableInitialState; mode: 'server'; onPaginationChange: (state: PaginationState) => void; onSortingChange?: (state: SortingState) => void; diff --git a/src/components/DataTable/utils.tsx b/src/components/DataTable/utils.tsx index 69171ba..0992229 100644 --- a/src/components/DataTable/utils.tsx +++ b/src/components/DataTable/utils.tsx @@ -14,6 +14,7 @@ import { DataTableRowActionCell } from './DataTableRowActionCell.tsx'; import type { BaseDataTableStoreParams, + ClientDataTableInitialState, DataTableColumnBreakpoints, DataTableRowAction, DataTableStoreParams, @@ -136,7 +137,10 @@ function getColumnPinningWithActions( } function getTanstackTableState({ initialState, rowActions }: DataTableStoreParams): TableState { - const { columnFilters = [], columnPinning = {}, sorting = [] } = initialState ?? {}; + // Widened to the client shape, which the server one is a subset of, so the union's narrower + // member does not make `columnFilters` and `sorting` unreadable here. + const initial: ClientDataTableInitialState = initialState ?? {}; + const { columnFilters = [], columnPinning = {}, sorting = [] } = initial; const state: TableState = { columnFilters, columnOrder: [],