import { ReactTable } from "./useTable.js"; import { AccessorFn, AccessorFnColumnDef, AccessorKeyColumnDef, Cell, CellContext, CellData, Column, ColumnDef, DeepKeys, DeepValue, DisplayColumnDef, GroupColumnDef, Header, IdentifiedColumnDef, NoInfer, Row, RowData, Table, TableFeatures, TableOptions, TableState } from "@tanstack/table-core"; import { ComponentType, Context, ReactNode } from "react"; //#region src/createTableHook.d.ts /** * Enhanced CellContext with pre-bound cell components. * The `cell` property includes the registered cellComponents. */ type AppCellContext>> = { cell: Cell & TCellComponents & { FlexRender: () => ReactNode; }; column: Column; getValue: CellContext['getValue']; renderValue: CellContext['renderValue']; row: Row; table: Table; }; /** * Enhanced HeaderContext with pre-bound header components. * The `header` property includes the registered headerComponents. */ type AppHeaderContext>> = { column: Column; header: Header & THeaderComponents & { FlexRender: () => ReactNode; }; table: Table; }; /** * Template type for column definitions that can be a string or a function. */ type AppColumnDefTemplate = string | ((props: TProps) => any); /** * Enhanced column definition base with pre-bound components in cell/header/footer contexts. */ type AppColumnDefBase>, THeaderComponents extends Record>> = Omit, 'cell' | 'header' | 'footer'> & { cell?: AppColumnDefTemplate>; header?: AppColumnDefTemplate>; footer?: AppColumnDefTemplate>; }; /** * Enhanced display column definition with pre-bound components. */ type AppDisplayColumnDef>, THeaderComponents extends Record>> = Omit, 'cell' | 'header' | 'footer'> & { cell?: AppColumnDefTemplate>; header?: AppColumnDefTemplate>; footer?: AppColumnDefTemplate>; }; /** * Enhanced group column definition with pre-bound components. */ type AppGroupColumnDef>, THeaderComponents extends Record>> = Omit, 'cell' | 'header' | 'footer' | 'columns'> & { cell?: AppColumnDefTemplate>; header?: AppColumnDefTemplate>; footer?: AppColumnDefTemplate>; columns?: ReadonlyArray>; }; /** * Enhanced column helper with pre-bound components in cell/header/footer contexts. * This enables TypeScript to know about the registered components when defining columns. */ type AppColumnHelper>, THeaderComponents extends Record>> = { /** * Creates a data column definition with an accessor key or function. * The cell, header, and footer contexts include pre-bound components. */ accessor: | DeepKeys, TValue extends (TAccessor extends AccessorFn ? TReturn : TAccessor extends DeepKeys ? DeepValue : never)>(accessor: TAccessor, column: TAccessor extends AccessorFn ? AppColumnDefBase & { id: string; } : AppColumnDefBase) => TAccessor extends AccessorFn ? AccessorFnColumnDef : AccessorKeyColumnDef; /** * Wraps an array of column definitions to preserve each column's individual TValue type. */ columns: >>(columns: [...TColumns]) => Array> & [...TColumns]; /** * Creates a display column definition for non-data columns. * The cell, header, and footer contexts include pre-bound components. */ display: (column: AppDisplayColumnDef) => DisplayColumnDef; /** * Creates a group column definition with nested child columns. * The cell, header, and footer contexts include pre-bound components. */ group: (column: AppGroupColumnDef) => GroupColumnDef; }; /** * Options for creating a table hook with pre-bound components and default table options. * Extends all TableOptions except 'columns' | 'data' | 'store' | 'state' | 'initialState'. */ type CreateTableHookOptions>, TCellComponents extends Record>, THeaderComponents extends Record>> = Omit, 'columns' | 'data' | 'store' | 'state' | 'initialState'> & { /** * Table-level components that need access to the table instance. * These are available directly on the table object returned by useAppTable. * Use `useTableContext()` inside these components. * @example { PaginationControls, GlobalFilter, RowCount } */ tableComponents?: TTableComponents; /** * Cell-level components that need access to the cell instance. * These are available on the cell object passed to AppCell's children. * Use `useCellContext()` inside these components. * @example { TextCell, NumberCell, DateCell, CurrencyCell } */ cellComponents?: TCellComponents; /** * Header-level components that need access to the header instance. * These are available on the header object passed to AppHeader/AppFooter's children. * Use `useHeaderContext()` inside these components. * @example { SortIndicator, ColumnFilter, ResizeHandle } */ headerComponents?: THeaderComponents; /** * A custom React context for the table instance (read with `useContext` inside * your `tableComponents`). Optional: defaults to a shared module-scoped context. * Only pass your own (created via `createContext`) when you need to isolate this * table's context from other tables, e.g. when nesting one table inside another. */ tableContext?: Context>; /** * A custom React context for the cell instance, used inside your `cellComponents`. * @see {@link CreateTableHookOptions.tableContext} */ cellContext?: Context>; /** * A custom React context for the header instance, used inside your * `headerComponents` (and footer components). * @see {@link CreateTableHookOptions.tableContext} */ headerContext?: Context>; }; interface CreateTableHookResult>, TCellComponents extends Record>, THeaderComponents extends Record>> { /** The features object that was passed to `createTableHook`. */ appFeatures: TFeatures; /** * A column helper pre-bound to `TFeatures` and the registered components, so * the cell/header/footer render props expose the bound components. */ createAppColumnHelper: () => AppColumnHelper; /** * Creates a table with the `App*` wrapper components and registered * `tableComponents` attached. `TData` is inferred from the `data` option. */ useAppTable: >(tableOptions: Omit, 'features'>, selector?: (state: TableState) => TSelected) => AppReactTable; /** * Reads the table provided by the nearest ``. This is the same * extended instance `useAppTable` returns, so the `App*` components and your * `tableComponents` are available on it. * * Pass `TSelected` to match the selector you gave `useAppTable`, so * `table.state` is typed as the selected slice. It cannot be inferred * automatically (React context does not carry the provider's generics), so it * defaults to the full table state, which is correct for the common case of * `useAppTable` without a selector. */ useTableContext: >() => AppReactTable; /** * Reads the cell provided by the nearest ``, extended with your * `cellComponents` and a context-bound `FlexRender`. */ useCellContext: () => Cell & TCellComponents & { FlexRender: () => ReactNode; }; /** * Reads the header provided by the nearest `` / * ``, extended with your `headerComponents` and a * context-bound `FlexRender`. */ useHeaderContext: () => Header & THeaderComponents & { FlexRender: () => ReactNode; }; } /** * Props for AppTable component - without selector */ interface AppTablePropsWithoutSelector { children: ReactNode; selector?: never; } /** * Props for AppTable component - with selector */ interface AppTablePropsWithSelector { children: (state: TSelected) => ReactNode; selector: (state: TableState) => TSelected; } /** * Props for AppCell component - without selector */ interface AppCellPropsWithoutSelector>> { cell: Cell; children: (cell: Cell & TCellComponents & { FlexRender: () => ReactNode; }) => ReactNode; selector?: never; } /** * Props for AppCell component - with selector */ interface AppCellPropsWithSelector>, TSelected> { cell: Cell; children: (cell: Cell & TCellComponents & { FlexRender: () => ReactNode; }, state: TSelected) => ReactNode; selector: (state: TableState) => TSelected; } /** * Props for AppHeader/AppFooter component - without selector */ interface AppHeaderPropsWithoutSelector>> { header: Header; children: (header: Header & THeaderComponents & { FlexRender: () => ReactNode; }) => ReactNode; selector?: never; } /** * Props for AppHeader/AppFooter component - with selector */ interface AppHeaderPropsWithSelector>, TSelected> { header: Header; children: (header: Header & THeaderComponents & { FlexRender: () => ReactNode; }, state: TSelected) => ReactNode; selector: (state: TableState) => TSelected; } /** * Component type for AppCell - wraps a cell and provides cell context with optional Subscribe */ interface AppCellComponent>> { (props: AppCellPropsWithoutSelector): ReactNode; (props: AppCellPropsWithSelector): ReactNode; } /** * Component type for AppHeader/AppFooter - wraps a header and provides header context with optional Subscribe */ interface AppHeaderComponent>> { (props: AppHeaderPropsWithoutSelector): ReactNode; (props: AppHeaderPropsWithSelector): ReactNode; } /** * Component type for AppTable - root wrapper with optional Subscribe */ interface AppTableComponent { (props: AppTablePropsWithoutSelector): ReactNode; (props: AppTablePropsWithSelector): ReactNode; } /** * Extended table API returned by useAppTable with all App wrapper components */ type AppReactTable>, TCellComponents extends Record>, THeaderComponents extends Record>> = ReactTable & NoInfer & { /** * Root wrapper component that provides table context with optional Subscribe. * @example * ```tsx * // Without selector - children is ReactNode * * ...
*
* * // With selector - children receives selected state * s.pagination}> * {(pagination) =>
Page {pagination.pageIndex}
} *
* ``` */ AppTable: AppTableComponent; /** * Wraps a cell and provides cell context with pre-bound cellComponents. * Optionally accepts a selector for Subscribe functionality. * @example * ```tsx * // Without selector * * {(c) => } * * * // With selector - children receives cell and selected state * s.columnFilters}> * {(c, filters) => {filters.length}} * * ``` */ AppCell: AppCellComponent>; /** * Wraps a header and provides header context with pre-bound headerComponents. * Optionally accepts a selector for Subscribe functionality. * @example * ```tsx * // Without selector * * {(h) => } * * * // With selector * s.sorting}> * {(h, sorting) => {sorting.length} sorted} * * ``` */ AppHeader: AppHeaderComponent>; /** * Wraps a footer and provides header context with pre-bound headerComponents. * Optionally accepts a selector for Subscribe functionality. * @example * ```tsx * * {(f) => } * * ``` */ AppFooter: AppHeaderComponent>; }; /** * Creates a custom table hook with pre-bound components for composition. * * This is the table equivalent of TanStack Form's `createFormHook`. It allows you to: * - Define features, row models, and default options once, shared across all tables * - Register reusable table, cell, and header components * - Access table/cell/header instances via context in those components * - Get a `useAppTable` hook that returns an extended table with App wrapper components * - Get a `createAppColumnHelper` function pre-bound to your features * * @example * ```tsx * // hooks/table.ts * export const { * useAppTable, * createAppColumnHelper, * useTableContext, * useCellContext, * useHeaderContext, * } = createTableHook({ * features: tableFeatures({ * rowPaginationFeature, * rowSortingFeature, * columnFilteringFeature, * paginatedRowModel: createPaginatedRowModel(), * sortedRowModel: createSortedRowModel(), * filteredRowModel: createFilteredRowModel(), * sortFns, * filterFns, * }), * tableComponents: { PaginationControls, RowCount }, * cellComponents: { TextCell, NumberCell }, * headerComponents: { SortIndicator, ColumnFilter }, * }) * * // Create column helper with TFeatures already bound * const columnHelper = createAppColumnHelper() * * // components/table-components.tsx * function PaginationControls() { * const table = useTableContext() // TFeatures already known! * return s.pagination}>... * } * * // features/users.tsx * function UsersTable({ data }: { data: Person[] }) { * const table = useAppTable({ * columns, * data, // TData inferred from Person[] * }) * * return ( * * * * {table.getHeaderGroups().map(headerGroup => ( * * {headerGroup.headers.map(h => ( * * {(header) => ( * * )} * * ))} * * ))} * * * {table.getRowModel().rows.map(row => ( * * {row.getAllCells().map(c => ( * * {(cell) => } * * ))} * * ))} * *
* * *
* *
* ) * } * ``` */ declare function createTableHook>, const TCellComponents extends Record>, const THeaderComponents extends Record>>({ tableComponents, cellComponents, headerComponents, tableContext, cellContext, headerContext, ...defaultTableOptions }: CreateTableHookOptions): CreateTableHookResult; //#endregion export { AppCellComponent, AppCellContext, AppCellPropsWithSelector, AppCellPropsWithoutSelector, AppColumnDefBase, AppColumnDefTemplate, AppColumnHelper, AppDisplayColumnDef, AppGroupColumnDef, AppHeaderComponent, AppHeaderContext, AppHeaderPropsWithSelector, AppHeaderPropsWithoutSelector, AppReactTable, AppTableComponent, AppTablePropsWithSelector, AppTablePropsWithoutSelector, CreateTableHookOptions, CreateTableHookResult, createTableHook };